Record
A Record is a new feature in Java 14+ (final in Java 16) that provides a compact way to create immutable data classes. Records automatically generate constructors, getter methods, equals(), hashCode(), and toString() — eliminating the boilerplate code that would usually be written by hand.
Records are similar to tuples in Python, but more powerful because they can have methods, constructor validation, and interface implementations. Each record's fields are defined in the header, and records are immutable — all fields are private final.
Records are perfect for DTOs (Data Transfer Objects), value objects, and data representations that do not need to be mutated. Java 16+ also supports the compact canonical constructor, which allows validation without writing a full constructor.
Record Features:
- Immutable by default — fields are automatically
private final - Auto-generated: constructor, getters,
equals(),hashCode(),toString() - Compact canonical constructor for validation
- Can implement interfaces (but cannot extend classes)
- Can have methods and static members
Code Example
// Simple record
record Student(String name, String studentId, double gpa) {}
// Record with validation
record Product(String name, double price) {
Product {
if (price < 0) throw new IllegalArgumentException("Price must not be negative");
name = name.trim();
}
// Custom method
double priceDiskon(double percent) {
return price * (1 - percent / 100);
}
}
public class RecordJava {
public static void main(String[] args) {
// Create a record
Student student = new Student("John", "123456", 3.75);
System.out.println(student); // Student[name=John, studentId=123456, gpa=3.75]
// Access fields (auto-generated getter methods)
System.out.println("Name: " + student.name());
System.out.println("Student ID: " + student.studentId());
System.out.println("GPA: " + student.gpa());
// Record with validation
Product p = new Product("Laptop", 15000000);
System.out.println("Discounted price: " + p.priceDiskon(10));
// Auto-generated equals()
Student student2 = new Student("John", "123456", 3.75);
System.out.println("Equal? " + student.equals(student2)); // true
}
}
Code Explanation
record Student(String name, String studentId, double gpa) {}— this single line already generates: a 3-parameter constructor, 3 getter methods (name(),studentId(),gpa()),equals(),hashCode(), andtoString().- Compact canonical constructor:
Product { ... }without a parameter list — you can add validation or field normalization before assignment. student.name()accesses the field (notstudent.name— the getter uses the method name without agetprefix).equals()compares based on the values of all fields, so two records with the same fields are considered equal.
Everyday Example
Records for representing address data and coordinates:
record Address(String street, String city, String province, String zipCode) {
Address {
street = street.trim();
city = city.trim().toUpperCase();
}
String summary() {
return city + ", " + province;
}
}
record Coordinates(double latitude, double longitude) {
Coordinates {
if (latitude < -90 || latitude > 90)
throw new IllegalArgumentException("Latitude must be -90 to 90");
if (longitude < -180 || longitude > 180)
throw new IllegalArgumentException("Longitude must be -180 to 180");
}
}
public class RecordKasus {
public static void main(String[] args) {
Address address = new Address("123 Main St", "new york", "New York City", "10220");
System.out.println(address);
System.out.println("Summary: " + address.summary());
Coordinates newYork = new Coordinates(40.7128, -74.0060);
System.out.println("New York coordinates: " + newYork);
}
}
Summary
Records are an important evolution in modern Java, eliminating boilerplate code for data classes. Being immutable by default with auto-generated methods, records make code cleaner, safer, and easier to maintain. Use records for DTOs, value objects, and simple data representations.