Java Records: A New Way to Handle Immutable Data
Pradeep Rai
π What is a Record?
Introduced in Java 14 (preview) and made stable in Java 16.
A record is a special kind of class designed to hold immutable data.
It automatically provides:
equals()hashCode()toString()- A constructor and getters for all fields.
π In short: A record is a concise way to create data carrier classes.
β When to Use Records
- When you need a data model class.
- For DTOs (Data Transfer Objects) in APIs.
- For database results mapping.
- When you want immutability and simplicity.
Example
1public record Person(String name, int age) {}
This is equivalent to a full POJO with private fields, constructor, getters, equals, hashCode, and toString.
β When NOT to Use Records
- When you need mutable fields.
- When your class has complex business logic.
- If inheritance is required β records cannot extend other classes (but they can implement interfaces).
- If you want to hide fields or not expose them as getters.
π Equals and HashCode in Records
Automatically generated based on all components.
Equality is value-based, not reference-based.
Example
1record Point(int x, int y) {} 2 3Point p1 = new Point(1, 2); 4Point p2 = new Point(1, 2); 5 6System.out.println(p1.equals(p2)); // true 7System.out.println(p1.hashCode() == p2.hashCode()); // true
ποΈ Canonical Constructor
The canonical constructor is the one that takes all record fields as parameters.
1public record User(String username, String email) { 2 // Canonical constructor 3 public User { 4 if (username == null || username.isBlank()) { 5 throw new IllegalArgumentException("Username cannot be empty"); 6 } 7 } 8}
Here, Java automatically maps parameters β fields. You can add validations but donβt need to write assignments manually.
π Examples
Simple Record
1record Book(String title, String author, double price) {}
Record with Validation
1record Employee(String id, String name, double salary) { 2 public Employee { 3 if (salary < 0) { 4 throw new IllegalArgumentException("Salary must be positive"); 5 } 6 } 7}
Record Implementing Interface
1interface Identifiable { 2 String id(); 3} 4 5record Student(String id, String name) implements Identifiable {}
β Trick Questions
Can records extend classes?
β No. They implicitly extend java.lang.Record.
Are records mutable?
β No. All fields are final.
Can records have static fields or methods?
β Yes, just like normal classes.
Can you add methods to a record?
β Yes, you can define additional methods.
Are records serializable?
β Yes, if all components are serializable.
Can you override equals and hashCode?
β Yes, but not recommended unless you have a strong reason.
π Conclusion
- Use records for simple, immutable data carriers.
- Avoid them for complex, mutable, or inheritance-heavy scenarios.
- They help write cleaner and more concise code with less boilerplate.