Кажется, с версии 17 в Джаве появились рекорды — они же записи. Клевая вещь, коротко про нее расскажу.

Запись — это класс с набором барахла, которое раньше нужно было писать руками. Только теперь это барахло производит компилятор. Например, если объявить запись с двумя полями:

public record User(name String, age int) {}

, то получим класс с полями name и int. Однако:

  • все поля финальные, их можно задать лишь однажды и никогда — изменить;

  • у класса готовый конструктор, в котором поля следуют в том порядке, что и в объявлении;

  • у класса готовые методы .name() и .age(), которые ведут себя как геттеры;

  • у класса свой метод .hash(), который учитывает все поля;

  • свой метод .equals(), который сравнивает записи по значениям;

  • удобный .toString(): напечатав запись, вы увидите значения полей, а не [foo.bar.User x00x0s0ds] (или что там печатает Джава по умолчанию).

Есть и другие плюсы, не помню все досконально.

Получается, на ровном месте появились нормальные неизменяемые классы. Всего-то двадцать лет прошло или около.

Хорошая привычка: пока это возможно, везде использовать рекорды, а к классам переходить, если состояние изменяется. В моем клиенте для Постгреса примерно так и сделано. Из 150 классов почти все из них — записи, и только корневой класс Connection — обычный Object.

Чтобы вы не подумали, что все так хорошо, вот ложка дегтя. Когда классы неизменяемы, часто нужен “такой же, но золотыми пуговицами”. Другими словами, получить клон экземпляра с измененным полем. Кложуристы поймут без слов:

(let [user {:name "Ivan" :age 10}]
  (assoc user :name "New"))

;; {:name "New", :age 10}

На мой взгляд, было бы логичным, если бы компилятор генерил методы .withName и .withAge, которые принимают значение и возвращают клон с новым полем. Но их нет, а прописывать вручную — скучно: это экраны кода, где, вдобавок, легко ошибиться.

Четыре года назад в Джаве сделали шаг в верном направлении. Хорошо, но мало. Не пора ли сделать еще? Глядишь, так и придем в светлое будущее.

Кстати, в Питоне тоже относительно недавно появились data-классы. Неужели адепты ООП стали что-то подозревать?