All topics
library
intermediate

Records (Java 14+)

Use records for immutable data carriers with auto-generated equals, hashCode, toString, and accessors.

A record declares the data and the compiler writes the rest.

Record = a pre-printed form with labeled fields. You fill in the values once (constructor) and they're locked. The form knows how to compare itself with other forms and describe itself.

Key Concepts

1
    record Point(int x, int y) { }
2
    // you get, for free:
    //   a constructor taking (x, y)
    //   accessors x() and y()
    //   equals comparing both components
    //   hashCode from both
    //   toString -> Point[x=1, y=2]
3
That replaces about fifty lines of fields, constructor, getters, equals, hashCode and toString — and removes the chance of equals and hashCode drifting apart as fields are added.
equalshashCodetoString
4
Accessors have no get prefix.
    p.x()            // not p.getX()
get
5
Validate with a compact constructor, which has no parameter list and no assignments:
6
    record Range(int lo, int hi) {
      Range {
        if (lo > hi) throw new IllegalArgumentException("lo > hi");
      }
    }
7
You may also normalise there — assigning to the parameter changes what gets stored:
8
    record Name(String value) {
      Name { value = value.trim(); }
    }
9
You can add anything that is not state.
    record Point(int x, int y) {
      double distance() { return Math.sqrt(x * x + y * y); }
      static Point origin() { return new Point(0, 0); }
    }
10
What a record cannot do.
    extend a class        it already extends java.lang.Record
    be extended           it is implicitly final
    hold mutable fields   every component is final
    add an instance field outside the component list
11
"Immutable" has a limit worth knowing.
    record Order(List<Item> items) { }
12
The items reference is final; the list is not. A caller can still add to it. For real immutability, copy in the constructor: items = List.copyOf(items).
itemsitems = List.copyOf(items)
13
Where records fit. DTOs, value objects, compound map keys, and returning two values from a method without inventing a class.
14
And they pair with sealed interfaces for exhaustive pattern matching, since a record is already final.
15
What the interviewer is probing.1. "Is a record immutable?" Probing: the limit of the guarantee. Stalls: "Yes, completely." Moves up: its components are final, but a component holding a List is still mutable by whoever passed it — copy in a compact constructor for real immutability.
16
2. "How do you validate a record component?" Probing: the compact constructor. Stalls: "You cannot." Moves up: a compact constructor with no parameter list and no assignments, which can throw or normalise by assigning to the parameter.
17
3. "What can a record not do?" Probing: the constraints. Stalls: "Nothing special." *Moves up:* extend a class, be extended, hold mutable instance fields, or declare instance fields outside the component list.
18
4. "Where do records fit beyond DTOs?" Probing: breadth. Stalls: "Just data transfer." Moves up: value objects, compound map keys, multiple return values, and sealed hierarchies for exhaustive pattern matching, since records are implicitly final.