Java records for immutable data classes
record syntax, canonical constructor, compact constructor, accessor methods, equals and hashCode, toString, record limitations, when to use records, record vs class
Records
Records (Java 16) are immutable data carriers. A single line replaces a class with constructor, accessors, equals(), hashCode(), and toString().
Defining a Record
public record Point(double x, double y) {}
This generates: canonical constructor, x(), y() accessors, equals(), hashCode(), and toString().
Point p1 = new Point(3.0, 4.0);
Point p2 = new Point(3.0, 4.0);
System.out.println(p1.x()); // 3.0
System.out.println(p1.equals(p2)); // true โ value comparison
System.out.println(p1); // Point[x=3.0, y=4.0]
Compact Constructor โ Validation
public record Range(int min, int max) {
public Range { // compact โ no parameter list
if (min > max) throw new IllegalArgumentException(
"min " + min + " > max " + max);
}
public int size() { return max - min; } // custom method
}
Records with Generics
public record Pair(A first, B second) {}
Pair p = new Pair<>("age", 30);
System.out.println(p.first() + ": " + p.second()); // age: 30
Record fields are implicitly private final. Records cannot extend classes (they implicitly extend Record) but can implement interfaces. Use records for DTOs, API responses, configuration objects, and any pure data carrier.
Records work naturally with Java's serialization and JSON libraries. Jackson can deserialize directly into records using the canonical constructor without requiring a no-arg constructor. This makes records ideal for API response models and event objects in event-driven architectures.
