Records
IntermediateDeclare immutable data carriers in one line — records auto-generate constructor, getters, equals, hashCode, and toString.
Overview
Records (Java 16, preview in 14/15) are a special class form for transparent data carriers. A record declaration like record Point(int x, int y) {} automatically generates: a canonical constructor, accessor methods x() and y(), equals(), hashCode(), and toString(). Records are implicitly final and all components are final. They are the perfect replacement for verbose POJO/DTO classes.
Declaring & Using Records
Record syntax: record Name(ComponentList) { optional body }. Components become private final fields with public accessor methods named after the component (not getX() — just x()). Records can implement interfaces, have static members, and have additional methods.
import java.util.*;
public class RecordDemo {
// Basic record — all boilerplate generated automatically
record Point(double x, double y) {
// Can add instance methods
public double distanceTo(Point other) {
double dx = this.x - other.x;
double dy = this.y - other.y;
return Math.sqrt(dx*dx + dy*dy);
}
// Static factory method
public static Point origin() { return new Point(0, 0); }
}
// Record implementing interface
interface Shape { double area(); }
record Circle(double radius) implements Shape {
// Compact constructor — validation only, no need to assign fields
Circle {
if (radius <= 0) throw new IllegalArgumentException("radius must be positive");
}
@Override public double area() { return Math.PI * radius * radius; }
}
public static void main(String[] args) {
var p1 = new Point(3, 4);
var p2 = Point.origin();
// Auto-generated accessors: x(), y() (not getX)
System.out.println(p1.x()); // 3.0
System.out.println(p1.y()); // 4.0
// Auto-generated toString
System.out.println(p1); // Point[x=3.0, y=4.0]
// Auto-generated equals + hashCode
var p3 = new Point(3, 4);
System.out.println(p1.equals(p3)); // true
System.out.println(p1 == p3); // false
System.out.println(p1.distanceTo(p2)); // 5.0
var c = new Circle(5);
System.out.printf("Area: %.2f%n", c.area()); // 78.54
try { new Circle(-1); } catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // radius must be positive
}
// Records work perfectly in collections
Set<Point> points = Set.of(p1, p2, new Point(1,1));
System.out.println(points.contains(new Point(3,4))); // true
}
}Canonical & Compact Constructors
The canonical constructor has the same signature as the component list. You can override it to add validation or transformation. The compact constructor omits the parameter list — the compiler provides the parameters and auto-assigns fields after the body runs. Use compact constructors for validation and normalisation.
import java.util.Objects;
public class ConstructorRecords {
// Custom canonical constructor
record Range(int min, int max) {
Range(int min, int max) {
if (min > max) throw new IllegalArgumentException("min > max");
this.min = min;
this.max = max;
}
public boolean contains(int value) { return value >= min && value <= max; }
}
// Compact constructor — normalise + validate
record PersonName(String first, String last) {
PersonName {
Objects.requireNonNull(first, "first name required");
Objects.requireNonNull(last, "last name required");
first = first.trim().toLowerCase(); // normalise
last = last.trim().toLowerCase();
// compiler assigns this.first = first, this.last = last automatically
}
public String fullName() {
return Character.toUpperCase(first.charAt(0)) + first.substring(1)
+ " "
+ Character.toUpperCase(last.charAt(0)) + last.substring(1);
}
}
public static void main(String[] args) {
var range = new Range(1, 10);
System.out.println(range.contains(5)); // true
System.out.println(range.contains(15)); // false
var name = new PersonName(" ALICE ", " Smith ");
System.out.println(name.first()); // alice
System.out.println(name.fullName()); // Alice Smith
}
}Records vs Classes & Limitations
Records cannot: extend another class (they implicitly extend Record), declare instance fields beyond components, be abstract, have mutable components (all are final). They can: implement interfaces, have static fields/methods, add instance methods, and be nested.
Ideal for: DTOs, value objects, API responses, Map keys (equals/hashCode auto-generated correctly).
import java.util.*;
import java.util.stream.*;
public class RecordPractice {
record Product(String id, String name, double price) {}
record PageResult<T>(List<T> items, int page, int totalPages) {}
public static void main(String[] args) {
var products = List.of(
new Product("p1", "Laptop", 999.0),
new Product("p2", "Phone", 699.0),
new Product("p3", "Tablet", 499.0)
);
// Records as Map keys — equals/hashCode just work
Map<Product, Integer> stock = new HashMap<>();
stock.put(products.get(0), 10);
stock.put(products.get(1), 25);
System.out.println(stock.get(new Product("p1","Laptop",999.0))); // 10
// Stream pipeline with records
var page = new PageResult<>(
products.stream()
.filter(p -> p.price() < 800)
.collect(Collectors.toList()),
1, 1);
System.out.println(page.items().size()); // 2
System.out.println(page); // PageResult[items=[...], page=1, totalPages=1]
// "Wither" pattern — create modified copy
var laptop = products.get(0);
var discounted = new Product(laptop.id(), laptop.name(), laptop.price() * 0.9);
System.out.println(discounted.price()); // 899.1
}
}Key Points to Remember
- record auto-generates canonical constructor, accessors (x() not getX()), equals, hashCode, toString
- Records are implicitly final — cannot be extended; all components are implicitly private final
- Compact constructor (no param list) auto-assigns fields after body — ideal for validation/normalisation
- Records can implement interfaces, add instance/static methods, and be generic
- Records make perfect Map keys and Set elements — equals/hashCode are correct by default
- Use records for DTOs, value objects, and any class whose purpose is to hold data
Practice Records in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is a record in Java and when was it introduced?
What methods does a record automatically generate?
What is a compact constructor in a record?
Can a record extend another class?
What is the difference between a record and a traditional POJO class?
Ask Aria about Records
Your personal AI tutor — ask anything about this concept