Java Records
A record is a class whose whole purpose is to carry data. You declare its components in the header, and the compiler writes the constructor, the accessors, equals, hashCode and toString. Nothing a data carrier needs is left for you to type by hand.
Records arrived in JDK 16 after two preview rounds, and they are the shortest path from "I need a pair of values" to a type that behaves correctly inside a collection. Demo 33 in the Lab Examples shows one with a validating constructor.
JDK 14 introduces records, which are a new kind of type declaration. Like an enum, a record is a restricted form of a class. It’s ideal for "plain data carriers," classes that contain data not meant to be altered and only the most fundamental methods such as constructors and accessors.
// A record declares its components in the header.
record Rectangle(double length, double width) { }
// The constructor, accessors, equals, hashCode and toString come for free.
Rectangle r = new Rectangle(4, 5);
System.out.println(r); // Rectangle[length=4.0, width=5.0]
System.out.println(r.length()); // 4.0
System.out.println(r.equals(new Rectangle(4, 5))); // true
Generated Members
A record class declares the following members automatically:
- For each component in the header, the following two members:
- A private final field with the same name and declared type as the record component. This field is sometimes referred to as a component field.
- A public accessor method with the same name and type of the component; in the Rectangle record class example, these methods are Rectangle::length() and Rectangle::width().
- A constructor whose signature is the same as the header. This constructor assigns each argument from the new expression that instantiates the record class to the corresponding component field.
- Implementations of the equals and hashCode methods, which specify that two record classes are equal if they are of the same type and contain equal component values.
- An implementation of the toString method that includes the string representation of all the record class's components, with their names.
Customizing a Record
A record is not a straitjacket. You may add methods, static factories, and a compact constructor that validates the components before they are assigned. What you cannot add is a mutable field or a setter: a record is immutable by construction, and that is the property that makes it safe to share between threads.
record Rectangle(double length, double width) {
// Compact constructor: no parameter list, the components are in scope.
Rectangle {
if (length <= 0 || width <= 0) {
throw new IllegalArgumentException("invalid dimensions");
}
}
// Records may still declare extra behaviour.
double area() {
return length * width;
}
}
Full details, including the rules for generic and local records, are in the JDK Records manual.