On this page
Records
Records (since Java 16) are a concise way to declare immutable data classes. The compiler automatically generates constructors, accessors, equals(), hashCode(), and toString().
Basic Record
public record Point(int x, int y) { }
Point p = new Point(3, 4);
System.out.println(p.x()); // 3 (not getX())
System.out.println(p); // Point[x=3, y=4]
System.out.println(p.equals(new Point(3, 4))); // true
A record implicitly:
- Is
finaland cannot be extended - Has private
finalfields for each component - Provides a public constructor matching the components
- Provides accessor methods named after components (no
getprefix)
Compact Constructor
Validate or normalize values without repeating field assignments:
public record Range(int start, int end) {
public Range {
if (start > end) {
throw new IllegalArgumentException("start must be <= end");
}
}
}
The compact constructor assigns fields automatically after it runs.
Custom Methods and Static Members
Records can have additional methods, static fields, and static methods:
public record Rectangle(double width, double height) {
public double area() {
return width * height;
}
public static Rectangle square(double side) {
return new Rectangle(side, side);
}
}
Implementing Interfaces
public record Person(String name, int age) implements Comparable<Person> {
@Override
public int compareTo(Person other) {
return Integer.compare(this.age, other.age);
}
}
Records vs Classes
| Feature | Record | Class |
|---|---|---|
| Purpose | Immutable data carrier | General-purpose object |
| Mutability | Immutable by design | Mutable by default |
| Inheritance | Cannot extend classes | Can extend one class |
| Boilerplate | Minimal | Requires manual equals/hashCode/toString |
| Fields | All final | Any modifier |
Limitations
- Cannot extend other classes (already extends
Record) - Cannot declare instance fields beyond the record components
- Are implicitly final — cannot be extended
- Cannot be abstract
When to Use Records
- DTOs (Data Transfer Objects)
- Value objects in domain models
- Return types grouping multiple values
- Keys in maps where equality matters
public record UserDto(Long id, String email, String role) { }
Map<UserDto, List<Order>> ordersByUser = new HashMap<>();
Best Practices
- Keep records focused on data — put complex behavior in separate service classes
- Use compact constructors for validation
- Prefer records over Lombok
@Valuefor simple immutable data types - Use
@Overridewhen customizingequals()ortoString()(rarely needed)