Loading...

Records

 

Java 16дан баштап, тилге жаңы функция кошулду - Records (орусча алар көбүнчө "запись" деп аталат). Records өзгөрүлгүс маалымат контейнерлерин түзүү үчүн иштелип чыккан класстар болуп саналат. Мындан тышкары, жазуулар коддун көлөмүн азайтуу менен иштеп чыгууну жөнөкөйлөштүрүүгө мүмкүндүк берет.

 

Records класстары record ачкыч сөзү менен аныкталат, андан кийин аты жана кашаадагы record талааларынын тизмеси:

record название (поле1, поле2,...полеN){

    // тело record

}

Төмөнкү мисалды карап көрөлү:

import java.util.Objects;

 

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom", 36);

        System.out.println(tom.toString());

    }

}

 

class Person {

    private final String name;

    private final int age;

 

    Person(String name, int age) {

        this.name = name;

        this.age = age;

    }

 

    String name() { return name; }

    int age() { return age; }

 

    public boolean equals(Object o) {

        if (!(o instanceof Person)) return false;

        Person other = (Person) o;

        return other.name == name && other.age == age;

    }

 

    public int hashCode() {

        return Objects.hash(name, age);

    }

 

    public String toString() {

        return String.format("Person[name=%s, age=%d]", name, age);

    }

}

Бул жерде Person классы аныкталат, ал эки константты аныктайт - name жана age:

private final String name;

private final int age;

Алардын баалуулуктары конструктордо белгиленет. Биз аларды мындан ары орното албайбыз. Ошентип, Person объекти түзүлгөндөн кийин, алар өзгөрүлгүс маалыматтарды сакташат.

 

name жана age баалуулуктарын алуу үчүн, ошол эле аталыштагы ыкмалары каралган:

String name() { return name; }

int age() { return age; }

Мындан тышкары, Object классынан мураска алынган equals(), hashCode() жана toString() методдору бул жерде жокко чыгарылат.

 

Негизги ыкмада биз Person классынын бир объектин түзөбүз жана анын тексттик көрүнүшүн консолго басып чыгарабыз:

Person tom = new Person("Tom", 36);

 System.out.println(tom.toString());

Натыйжада, консол бизге көрсөтөт:

Person[name=Tom, age=36]

Эми Records бизге эмне сунуштаарын карап көрөлү - келгиле рекордду аныктайлы, ал жогоруда аныкталган класска толугу менен окшош болот:

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom", 36);

        System.out.println(tom.toString());

    }

}

record Person(String name, int age) { }

Жазуулар жазуунун аталышынан кийин жазуу ачкыч сөзү менен аныкталат. Кийинки жазуу талааларынын тизмеси келет. Башкача айтканда, бул учурда эки талаа аныкталат - аты жана жашы. Жана демейки боюнча, алардын баары купуя жана акыркы өзгөрткүчкө ээ болот.

 

Ал ошондой эле эки параметр аты жана жашы менен конструктор түзөт. Жана ар бир талаа үчүн бул талаанын маанисин алуу үчүн автоматтык түрдө бирдей аталыштагы жалпыга маалымдоо ыкмасы түзүлөт. Мисалы, ат талаасынын маанисин кайтаруучу name() ыкмасы түзүлөт.

Жана тең, hashCode жана toString ыкмалары да автоматтык түрдө түзүлөт. Жалпысынан алганда, бул жазуу жогоруда аныкталган класска толугу менен окшош болот, бирок ал бир топ азыраак кодду камтыйт.

 

Зарыл болсо, биз бардык жеткиликтүү ыкмаларды чакыра алабыз:

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom",  36);

        

        System.out.println(tom.name());     // Tom

        System.out.println(tom.age());      // 36

        System.out.println(tom.hashCode());

        

        Person bob = new Person("Bob", 21);

        Person tomas = new Person("Tom", 36);

        System.out.println(tom.equals(bob));    // false

        System.out.println(tom.equals(tomas));  // true

    }

}

record Person(String name, int age){ }

рекорд конструктор

Жогорудагы мисалда жазуу формасы колдонулган:

record Person(String name, int age) { }

чындыгында конструкторду жараткан:

Person(String name, int age) {

    this.name = name;

    this.age = age;

}

Бул конструктор канондук деп аталат. Ал жазуу талаалары менен бирдей аталган параметрлерди алат жана тиешелүү параметрлердин маанилерин талааларга өткөрүп берет.

 

Бирок, керек болсо, конструктордун логикасын өзгөртө алабыз. Ошентип, биз конструктордун логикасын жокко чыгара алабыз. Мисалы, объектти түзүүдө жараксыз жаш өтүп кетсечи? Келгиле, конструктор логикасын кайра аныктоо менен бул жагдайды алдын ала көрөлү:

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom", -116);

        System.out.println(tom.toString());

    }

}

record Person(String name, int age) {

 

    Person{

        

        if(age<1 || age > 110){

            age = 18;

        }

    }

}

Бул учурда, эгерде жараксыз маани берилсе, анда биз кандайдыр бир демейки маанини колдонобуз (сан 18). Натыйжада, иш жүзүндө, биз төмөнкү иш менен конструкторду алабыз:

Person(String name, int age) {

    if(age<1 || age > 110){

        age = 18;

    }

    this.name = name;

    this.age = age;

}

Натыйжада, программа консолдо төмөнкүлөрдү көрсөтөт:

Person[name=Tom, age=18]

Биз толугу менен канондук конструкторду жокко чыгара алабыз:

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom",  36);

        System.out.println(tom.toString());

        System.out.println(tom.name());

    }

}

record Person(String name, int age) {

 

    Person(String name, int age){

        

        if(age < 0 || age > 120) age = 18;

        

        this.name = name;

        this.age = age;

    }

}

Биз башка конструкторлорду да аныктай алабыз, бирок алардын баары канондук конструкторду чакырышы керек:

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom", "Smith",  36);

        System.out.println(tom.toString());

    }

}

record Person(String name, int age) {

 

    Person(String firstName, String lastName, int age){

        

        this(firstName + " " + lastName, age);

        

    }

}

Бул шарттуу түрдө колдонуучунун атын, фамилиясын жана жашын кабыл алган конструкторду аныктайт. Бул конструктор канондук конструкторду чакырып, ага ат жана жаш талааларынын маанилерин берет: this(firstName + " " + фамилиясы, жашы).

 

Программанын консолдук натыйжасы:

Person[name=Tom Smith, age=36]

Өткөрүүчү методдор

Биз ошондой эле демейки боюнча жазылган ыкмаларды жокко чыгара алабыз. Жана бул теңдештирилген(), hashCode() жана toString() методдору жана методдору, алар жазуу талаалары менен бирдей аталган жана тиешелүү талаалардын маанилерин кайтарат.

 

Мисалы, Person жазуусу үчүн toString() жана name() ыкмаларын жокко чыгаралы:

public class Program{

      

    public static void main (String args[]){

          

        Person tom = new Person("Tom", 36);

        System.out.println(tom.toString());

        System.out.println(tom.name());

    }

}

record Person(String name, int age) {

 

    public String name() { return "Mister " + name; }

    

    public String toString() {

        return String.format("Person %s, Age: %d", name, age);

    }

}

Программалардын консолдук чыгарылышы:

Person Tom, Age: 36

Mister Tom

Чектөө жазуулары

Жазууну башка класстардан мурастай албай турганыбызды эске алыңыз. Сиз ошондой эле жазуулардан класстарды мурастай албайсыз. Бирок, рекорд класстары интерфейстерди ишке ашыра алат. Ошондой эле, рекорд класстар абстракттуу болушу мүмкүн эмес.

 

Жаздыруу статикалык эмес талааларды жана инициализаторлорду ачык аныктай албайт. Бирок сиз статикалык өзгөрмөлөрдү жана инициализаторлорду, ошондой эле статикалык жана статикалык эмес методдорду аныктай аласыз:

record Person(String name, int age){

 

    static int minAge;

    static{

        minAge = 18;

        System.out.println("Static initializer");

    }

}