Записи, классы и Lombok
Сравнивайте записи с традиционными классами и аннотациями Lombok, чтобы выбрать подходящий инструмент.
«Записи, классы и Lombok» — бесплатный урок Java Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Записи, классы и Lombok
Java предлагает несколько подходов к созданию типов, переносящих данные: обычные классы с шаблонным кодом, записи (Java 16 и новее) или аннотации Lombok. Правильный выбор зависит от конкретного случая использования.
Проблема шаблонного кода
Обычный класс Java для простого носителя данных требует много шаблонного кода: конструктор, методы доступа, equals, hashCode и toString — и всё это всего для нескольких полей.
// Traditional class — lots of boilerplate
class ProductOld {
private final String id;
private final String name;
private final double price;
public ProductOld(String id, String name, double price) {
this.id = id; this.name = name; this.price = price;
}
public String getId() { return id; }
public String getName() { return name; }
public double getPrice() { return price; }
@Override public boolean equals(Object o) { /* ... */ }
@Override public int hashCode() { /* ... */ }
@Override public String toString() { /* ... */ }
}Решение с записями
Запись сокращает тот же класс до одной строки. Компилятор автоматически создаёт весь шаблонный код.
// Record — one line, same functionality
record Product(String id, String name, double price) {}
// Usage is almost identical except accessors use component names (no get prefix)
Product p = new Product("P001", "Laptop", 999.99);
System.out.println(p.id()); // P001 (not getId())
System.out.println(p.name()); // Laptop
System.out.println(p.price()); // 999.99
System.out.println(p); // Product[id=P001, name=Laptop, price=999.99]Lombok @Data и @Value
Lombok создаёт шаблонный код на этапе компиляции с помощью аннотаций. @Value создаёт неизменяемый класс, похожий на запись, а @Data — изменяемый класс.
// Lombok @Value — immutable (closest to record)
import lombok.Value;
@Value
public class LombokProduct {
String id;
String name;
double price;
// Lombok generates: all-args constructor, getters, equals, hashCode, toString
// Note: accessors follow getX() naming convention (getPrice(), not price())
}
// Lombok @Data — mutable
import lombok.Data;
@Data
public class MutableProduct {
private String id;
private String name;
private double price;
// Generates: getters, setters, equals, hashCode, toString, no-args constructor
}Ключевые различия
Важные различия между записями, Lombok @Value и обычными классами:
- Именование методов доступа: записи используют
name(), а Lombok —getName() - Изменяемый вариант: записи всегда неизменяемы, а Lombok предлагает @Data для изменяемости
- Наследование: записи не могут расширять классы, а классы Lombok могут
- Зависимость от инструмента сборки: Lombok требует настройки процессора аннотаций, а записи встроены в Java
Когда использовать записи
Записи идеально подходят, когда:
- Тип в первую очередь является прозрачным контейнером данных (объектом передачи данных или объектом значения)
- Неизменяемость заложена в проекте
- Вы используете Java 16 или более новую версию и хотите обойтись без зависимостей
- Тип участвует в сопоставлении с образцом (запечатанные классы + записи)
// Perfect record use cases:
record Coordinates(double lat, double lon) {}
record JwtClaims(String subject, String role, long expiresAt) {}
record PageRequest(int page, int size, String sortBy) {}
record ErrorResponse(int code, String message, String path) {}
// These are all simple data carriers with no mutable stateКогда использовать Lombok
Lombok предпочтителен, когда:
- Вам нужны изменяемые компоненты (например, сущности JPA или классы конфигурации Spring)
- Для совместимости с платформами имена методов доступа должны соответствовать соглашению JavaBeans (
getX) - Вам нужен
@Builderдля сложного создания объектов - Требуется частичная изменяемость (
@NonFinalу некоторых полей)
// Lombok @Builder — great for complex object construction
import lombok.*;
@Builder
@Value
public class EmailMessage {
String to;
String from;
String subject;
String body;
List<String> attachments;
}
EmailMessage msg = EmailMessage.builder()
.to("user@example.com")
.from("noreply@app.com")
.subject("Welcome!")
.body("Thank you for signing up")
.attachments(List.of())
.build();Когда использовать обычные классы
Обычные классы по-прежнему уместны, когда:
- Класс обладает сложным поведением, выходящим за рамки простого хранения данных
- Вам нужно расширить другой класс
- Требуется детальный контроль над hashCode и equals
- Требуется изменяемое состояние с инкапсуляцией
// Plain class — when behavior dominates over data
class ShoppingCart {
private final List<CartItem> items = new ArrayList<>();
private final String customerId;
public ShoppingCart(String customerId) {
this.customerId = customerId;
}
public void addItem(CartItem item) { items.add(item); }
public void removeItem(String sku) { items.removeIf(i -> i.sku().equals(sku)); }
public double total() { return items.stream().mapToDouble(CartItem::lineTotal).sum(); }
public boolean isEmpty() { return items.isEmpty(); }
}Сочетание записей и классов
Записи и классы без проблем работают вместе. Используйте записи для неизменяемых данных внутри классов, управляющих изменяемым состоянием.
// Record for the immutable event data
record UserEvent(String userId, String action, java.time.Instant timestamp) {
public static UserEvent now(String userId, String action) {
return new UserEvent(userId, action, java.time.Instant.now());
}
}
// Class for the mutable event store
class EventLog {
private final List<UserEvent> events = new ArrayList<>();
public void record(String userId, String action) {
events.add(UserEvent.now(userId, action));
}
public List<UserEvent> eventsFor(String userId) {
return events.stream()
.filter(e -> e.userId().equals(userId)).toList();
}
}Записи в Spring Boot
Записи хорошо интегрируются со Spring Boot в качестве тел запросов и ответов. Сопоставитель Jackson в Spring обрабатывает их при минимальной настройке.
// Spring Boot REST controller using records
import org.springframework.web.bind.annotation.*;
record CreateProductRequest(String name, double price, String category) {}
record ProductResponse(long id, String name, double price, String category) {}
@RestController
@RequestMapping("/api/products")
class ProductController {
@PostMapping
public ProductResponse create(@RequestBody CreateProductRequest req) {
// Jackson automatically deserializes JSON into the record
long id = productService.save(req);
return new ProductResponse(id, req.name(), req.price(), req.category());
}
}Сравнение производительности
Все три подхода создают практически одинаковый байткод для простых контейнеров данных. Производительность идентична — выбор зависит от удобства разработки и требований.
// All three compile to approximately equivalent bytecode:
// - Records: compiler-generated, always immutable
// - Lombok @Value: annotation-processor-generated, always immutable
// - Plain class: hand-written
// The key runtime difference:
// Records: accessor is a method matching field name (price() not getPrice())
// Lombok/Class: accessor follows JavaBeans (getPrice())
// Jackson compatibility:
// Records: work natively in Jackson 2.12+ with no config
// Lombok: work with @JsonProperty or jackson-databind-lombok moduleБыстрая проверка
Какому соглашению об именовании следуют методы доступа записей?
Итоги: записи, классы и Lombok
Главные выводы:
- Записи автоматически создают конструктор, методы доступа (без префикса get), equals, hashCode и toString
- Записи всегда неизменяемы; для изменяемого состояния используйте обычные классы
- Lombok @Value приближается по возможностям к записям, но использует имена getX() и требует настройки
- Lombok @Builder отлично подходит для сложного создания объектов с множеством необязательных полей
- Записи идеально подходят для объектов передачи данных, объектов значений и тел запросов и ответов программного интерфейса
- Обычные классы остаются лучшим выбором, когда основную роль играет поведение или требуется наследование
Изучай Java с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 104
- Уроки
- 374
Часто задаваемые вопросы
Урок «Записи, классы и Lombok» бесплатный?
Да — полный текст урока «Записи, классы и Lombok» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Записи, классы и Lombok»?
Сравнивайте записи с традиционными классами и аннотациями Lombok, чтобы выбрать подходящий инструмент. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Записи, классы и Lombok»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Знакомство с записями
- Компактные конструкторы и проверка данных
- Пользовательские методы в записях
- Записи, классы и Lombok