Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Записи (record)

Многие классы просто хранят данные: точка, товар, адрес. Для них приходится писать конструктор, геттеры, equals(), hashCode() и toString(). Запись (record) делает всё это за вас одной строкой.

Первая запись

После слова record указывают имя и в скобках — компоненты, то есть поля записи. Java сама создаёт конструктор и методы чтения:

record Point(int x, int y) {}
 
void main() {
    Point p = new Point(3, 4);
    IO.println(p.x());
    IO.println(p.y());
}

Результат:

3
4

Методы чтения называются так же, как компоненты: x(), а не getX().

Готовые toString и equals

Запись печатается в понятном виде и сравнивается по содержимому. Метод hashCode() тоже согласован с equals(), поэтому записи можно смело класть в HashSet и использовать как ключи HashMap:

record Product(String title, double price) {}
 
void main() {
    Product a = new Product("Чай", 4.5);
    Product b = new Product("Чай", 4.5);
    IO.println(a);
    IO.println(a.equals(b));
}

Результат:

Product[title=Чай, price=4.5]
true

Записи неизменяемы

Все поля записи — private final. Изменить объект после создания нельзя, вместо этого создают новый с нужными значениями:

record Product(String title, double price) {
    Product withPrice(double newPrice) {
        return new Product(title, newPrice);
    }
}
 
void main() {
    Product tea = new Product("Чай", 4.5);
    Product cheaper = tea.withPrice(3.9);
    IO.println(tea);
    IO.println(cheaper);
}

Результат:

Product[title=Чай, price=4.5]
Product[title=Чай, price=3.9]

Как видно, в записи можно объявлять свои методы — как в обычном классе.

Компактный конструктор

Чтобы проверить данные, пишут компактный конструктор: без списка параметров, только имя записи. Присваивать поля в нём не нужно — Java сделает это после проверки:

record Age(int years) {
    Age {
        if (years < 0) {
            throw new IllegalArgumentException("Возраст не может быть отрицательным: " + years);
        }
    }
}
 
void main() {
    IO.println(new Age(30));
    IO.println(new Age(-1));
}

Результат:

Age[years=30]
Exception in thread "main" java.lang.IllegalArgumentException: Возраст не может быть отрицательным: -1

Когда использовать запись

Запись подходит для простых «носителей данных»: результатов вычислений, строк таблицы, сообщений между частями программы. Записи не могут наследовать другие классы, зато могут реализовывать интерфейсы. Если объекту нужно менять своё состояние, нужен обычный класс.

Частая ошибка

Поле записи нельзя изменить даже внутри её собственного метода — оно final:

record Counter(int value) {
    void increment() {
        value++;
    }
}
 
void main() {
}

Результат:

Main.java:3: error: cannot assign a value to final variable value
        value++;
        ^

Возвращайте новую запись: Counter increment() { return new Counter(value + 1); }.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.