Record (Java 16+ — JEP 395) là class đặc biệt cho dữ liệu bất biến.
Một dòng thay 50 dòng POJO.
public record Person(String name, int age) {}
// Tương đương ~50 dòng POJO với constructor + getter + equals + hashCode + toStringCompiler tự sinh: constructor canonical, accessor name() / age() (không có "get"), equals / hashCode / toString, field ngầm private final.
Tuỳ biến qua compact constructor:
public record Person(String name, int age) {
public Person { // compact constructor
if (age < 0) throw new IllegalArgumentException("age >= 0");
name = name.trim();
}
public boolean isAdult() { return age >= 18; } // method tự định nghĩa
}Khi nên dùng:
- DTO chuyển dữ liệu giữa layer.
- API request/response (Spring Boot 3 hỗ trợ Jackson + Validator).
- Value object DDD: Money, Coordinate, EmailAddress.
- Map key / Set element.
Hạn chế:
- Không extends class khác — chỉ implements interface.
- Implicitly final, không subclass được.
- Không phù hợp JPA entity (cần setter + no-arg constructor).
Record Patterns (Java 21): bóc field ngay trong pattern matching:
if (shape instanceof Circle(double r)) return Math.PI * r * r;Chốt: record là default cho immutable data; class truyền thống chỉ khi cần state mutable hoặc framework yêu cầu.
Records (Java 16+ — JEP 395) are a special class for immutable data carriers.
One line replaces 50 lines of POJO.
public record Person(String name, int age) {}
// Equivalent to ~50 lines of POJO with constructor + getters + equals + hashCode + toStringThe compiler generates: canonical constructor, accessors name() / age() (no get prefix), equals / hashCode / toString, fields implicitly private final.
Customise via compact constructor:
public record Person(String name, int age) {
public Person { // compact constructor
if (age < 0) throw new IllegalArgumentException("age >= 0");
name = name.trim();
}
public boolean isAdult() { return age >= 18; } // custom method
}When to use:
- DTOs between layers.
- API request/response (Spring Boot 3 supports Jackson + Validator).
- Value objects in DDD: Money, Coordinate, EmailAddress.
- Map keys / Set elements.
Limitations:
- Cannot extends another class — only implements interfaces.
- Implicitly final, cannot be subclassed.
- Unsuitable for JPA entities (need setters + no-arg constructor).
Record Patterns (Java 21): destructure fields directly in pattern matching:
if (shape instanceof Circle(double r)) return Math.PI * r * r;Bottom line: records are the default for immutable data; reach for traditional classes only when you need mutable state or a framework demands it.