Immutable data carriers without boilerplate — records replace POJOs in most scenarios.
Published February 15, 2025
Records are immutable data classes that eliminate boilerplate. A record automatically generates:
equals() and hashCode()toString()name() not getName())// Traditional class — ~30 lines
public final class Point {
private final int x;
private final int y;
// constructor, getters, equals, hashCode, toString ...
}
// Record — 1 line
record Point(int x, int y) {}
Point p = new Point(3, 4);
p.x(); // 3 — accessor
p.y(); // 4
p.toString(); // Point[x=3, y=4]
record User(String name, String email) {
// Compact constructor — runs before all components are assigned
User {
Objects.requireNonNull(name, "name required");
email = email.toLowerCase(); // normalize
}
// Custom methods are allowed
public boolean isPremium() {
return email.endsWith("@company.com");
}
}
Records work perfectly as DTOs and response objects:
@RestController
public class UserController {
record UserResponse(String id, String name, String email) {}
@GetMapping("/users/{id}")
public UserResponse getUser(@PathVariable String id) {
return new UserResponse(id, "Alice", "alice@example.com");
}
}
Records are great for compound keys in hash maps:
record Pair(int row, int col) {} // as a HashMap key
Map<Pair, Integer> visited = new HashMap<>();
visited.put(new Pair(0, 0), 0);
final — cannot extend another class (but can implement interfaces)private final — no mutable stateRecords are the idiomatic way to create value objects in modern Java. If asked about DTO design in Spring Boot, mention records as the clean solution.