Rekordy a klasy i Lombok
Porównuj rekordy z tradycyjnymi klasami i adnotacjami Lombok, aby wybrać właściwe narzędzie.
Rekordy a klasy i Lombok to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Rekordy a klasy i Lombok
Java oferuje kilka sposobów tworzenia typów przenoszących dane: zwykłe klasy z kodem pomocniczym, rekordy (Java 16+) lub adnotacje Lombok. Wybór właściwego rozwiązania zależy od przypadku użycia.
Problem nadmiarowego kodu
Zwykła klasa Java będąca prostym nośnikiem danych wymaga znacznej ilości kodu pomocniczego: konstruktora, metod dostępowych, equals, hashCode i toString — a wszystko to zaledwie dla kilku pól.
// 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() { /* ... */ }
}Rozwiązanie w postaci rekordu
Rekord skraca tę samą klasę do jednego wiersza. Kompilator automatycznie generuje cały kod pomocniczy.
// 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 i @Value
Lombok generuje kod pomocniczy podczas kompilacji za pomocą adnotacji. @Value tworzy niezmienną klasę podobną do rekordów, a @Data tworzy klasę zmienną.
// 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
}Najważniejsze różnice
Najważniejsze różnice między rekordami, Lombok @Value a zwykłymi klasami:
- Nazewnictwo akcesorów: rekordy używają
name(), a Lombok —getName() - Wariant mutowalny: rekordy są zawsze niemutowalne, natomiast Lombok udostępnia @Data do tworzenia obiektów mutowalnych
- Dziedziczenie: rekordy nie mogą rozszerzać klas, a klasy Lombok mogą
- Zależność od narzędzia budującego: Lombok wymaga konfiguracji procesora adnotacji, natomiast rekordy są wbudowane w język
Kiedy używać rekordów
Rekordy są idealne, gdy:
- Typ służy przede wszystkim jako przejrzysty nośnik danych (DTO, Value Object)
- Z założenia wymagana jest niemutowalność
- Używają Państwo Java 16 lub nowszej wersji i chcą uniknąć zależności
- Typ uczestniczy w dopasowywaniu wzorców (sealed + records)
// 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 stateKiedy używać Lombok
Lombok jest preferowany, gdy:
- Potrzebne są mutowalne beany (np. encje JPA lub klasy konfiguracyjne Spring)
- Nazewnictwo akcesorów musi być zgodne z konwencją JavaBeans (
getX) ze względu na zgodność z frameworkami - Potrzebują Państwo
@Builderdo konstruowania złożonych obiektów - Wymagana jest częściowa mutowalność (
@NonFinaldla wybranych pól)
// 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();Kiedy używać zwykłych klas
Zwykłe klasy pozostają odpowiednie, gdy:
- Klasa zawiera złożone zachowanie wykraczające poza proste przechowywanie danych
- Trzeba rozszerzyć inną klasę
- Potrzebna jest szczegółowa kontrola nad implementacją hashCode/equals
- Wymagany jest mutowalny stan z zachowaniem enkapsulacji
// 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(); }
}Łączenie rekordów i klas
Rekordy i klasy współpracują ze sobą bez problemu. Rekordów należy używać do przechowywania niemutowalnych danych wewnątrz klas zarządzających mutowalnym stanem.
// 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();
}
}Rekordy w Spring Boot
Rekordy dobrze integrują się z Spring Boot jako ciała żądań i odpowiedzi. Mapper Jacksona używany przez Spring obsługuje je przy minimalnej konfiguracji.
// 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());
}
}Porównanie wydajności
Wszystkie trzy podejścia generują zasadniczo taki sam bytecode dla prostych nośników danych. Wydajność jest identyczna — wybór zależy od komfortu programistów i wymagań.
// 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 moduleSzybkie sprawdzenie
Jaką konwencję nazewnictwa stosują akcesory rekordów?
Podsumowanie: rekordy a klasy i Lombok
Najważniejsze informacje:
- Rekordy automatycznie generują konstruktor, akcesory (bez prefiksu get), equals, hashCode i toString
- Rekordy są zawsze niemutowalne; do przechowywania mutowalnego stanu należy używać zwykłych klas
- Lombok @Value w przybliżeniu odwzorowuje rekordy, ale używa nazewnictwa getX() i wymaga konfiguracji
- Lombok @Builder sprawdza się przy konstruowaniu złożonych obiektów z wieloma opcjonalnymi polami
- Rekordy są idealne dla DTO, obiektów wartości oraz ciał żądań i odpowiedzi API
- Zwykłe klasy pozostają najlepszym wyborem, gdy najważniejsze jest zachowanie lub potrzebne jest dziedziczenie
Często zadawane pytania
Czy lekcja „Rekordy a klasy i Lombok” jest bezpłatna?
Tak — pełny tekst „Rekordy a klasy i Lombok” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Rekordy a klasy i Lombok”?
Porównuj rekordy z tradycyjnymi klasami i adnotacjami Lombok, aby wybrać właściwe narzędzie. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Rekordy a klasy i Lombok”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wprowadzenie do rekordów
- Kompaktowe konstruktory i walidacja
- Własne metody w rekordach
- Rekordy a klasy i Lombok