junior
Records — что это и зачем?
Record — компактный способ объявления классов-носителей неизменяемых данных (data carriers). Компилятор автоматически генерирует конструктор, accessor-методы, equals(), hashCode() и toString().
Аналогия из жизни: record — как бланк паспорта: поля фиксированы (имя, дата рождения, номер), нельзя добавить новые, нельзя изменить заполненные. Вы просто указываете, какие данные нужны, а формат генерируется автоматически.
Пример: Record vs обычный класс
// Record — одна строка вместо ~50 строк boilerplate
public record Point(int x, int y) {}
// Эквивалентный обычный класс:
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() { return x; } // не getX()!
public int y() { return y; }
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() { ... }
@Override
public String toString() { return "Point[x=" + x + ", y=" + y + "]"; }
}
Использование
Пример
var p = new Point(10, 20);
int x = p.x(); // accessor (не getX!)
System.out.println(p); // Point[x=10, y=20]
// Compact constructor — валидация
public record Email(String value) {
public Email { // compact canonical constructor
if (value == null || !value.contains("@")) {
throw new IllegalArgumentException("Invalid email: " + value);
}
value = value.toLowerCase().strip();
}
}
// Record с дополнительными методами
public record Range(int from, int to) {
public Range {
if (from > to) throw new IllegalArgumentException();
}
public int length() { return to - from; }
public boolean contains(int value) { return value >= from && value <= to; }
}
Ограничения Records
| Ограничение | Причина |
|---|---|
| Нельзя наследоваться от другого класса | Неявно наследует java.lang.Record |
| Нельзя объявлять instance-поля | Только компоненты записи |
| Все поля final и private | Неизменяемость по контракту |
| Record implicitly final | Нельзя наследоваться от record |
| Нельзя как JPA Entity | Entity требует no-arg constructor и мутабельность |
Частые ошибки
- Мутабельные поля в Record —
record Data(List<String> items)— список мутабельный; делайте defensive copy:this.items = List.copyOf(items) - Record как JPA Entity — нельзя; Record можно как DTO или
@Embeddable - Ожидать
getX()вместоx()— Jackson и другие библиотеки поддерживают record accessors, но legacy-код может ожидать JavaBean-стиль
Как используется в 2026
- Records — стандарт для DTO, Value Objects, API responses/requests
- Широкая поддержка: Jackson, Spring, Hibernate (Embeddable), MapStruct
- В комбинации с Sealed Interfaces — алгебраические типы данных
- Record Patterns (Java 21) — деконструкция records в switch/instanceof
На собеседовании: не забудьте упомянуть compact constructor (валидация без явного присвоения полей), accessor без get-префикса (
x()вместоgetX()), и невозможность использования как JPA Entity. Частая ошибка — не знать про defensive copy для мутабельных компонентов.