Records (Java 16+)
Immutable data carriers — auto-generated constructor, accessors, equals, hashCode, toString.
Records: data classes without the boilerplate
A record is a restricted class whose primary purpose is carrying immutable data. The declaration is concise:
public record Point(int x, int y) { }
The compiler automatically generates:
- A canonical constructor Point(int x, int y) that assigns all components.
- Accessor methods x() and y() — note: no getX()/getY().
- equals, hashCode, and toString based on all components.
Point p1 = new Point(3, 4);
Point p2 = new Point(3, 4);
System.out.println(p1.x()); // 3 — accessor, not getX()
System.out.println(p1.equals(p2)); // true — value equality
System.out.println(p1); // Point[x=3, y=4]
Compact canonical constructor — validation
To add validation without duplicating assignment code, use a compact canonical constructor (no parameter list — it inherits the record's parameters):
public record Range(int lo, int hi) {
Range { // compact form — no (int lo, int hi)
if (lo > hi)
throw new IllegalArgumentException(lo + " > " + hi);
// assignment of fields happens automatically after this block
}
}
What records cannot do
- Records are implicitly final — they cannot be extended.
- Component fields are implicitly private final — they cannot be mutated.
- Records cannot extend another class (they already extend java.lang.Record).
- Records can implement interfaces.