A Java record is a special kind of class for representing a fixed set of named values with less boilerplate than a conventional class. The compiler supplies its component fields, accessors, canonical constructor, and implementations of equals, hashCode, and toString. Records became a permanent Java feature in Java SE 16 after preview releases in Java SE 14 and 15.
What a Java record declares
In a record declaration, the header names the data components and their types:
public record Rectangle(double length, double width) { }
This declaration makes length and width the record’s components. The compiler provides a private final field and a public accessor for each component, a canonical constructor that accepts the components, and implementations of equals, hashCode, and toString. Accessors use the component name, so callers write rectangle.length(), not rectangle.getLength().
Records are still classes: create them with new, use them as method parameters or return values, and add members when needed. Oracle describes record classes as a way to model plain data aggregates with less ceremony than ordinary classes (Oracle’s Java records guide).
Are Java records immutable?
Records are shallowly immutable. Their component fields are final, so a component reference cannot be reassigned after construction. But if a component refers to a mutable object, that object may still change. A record containing a list, for example, does not automatically make the list immutable.
Copy mutable inputs when constructing a record if callers should not retain a reference they can use to change its contents. An explicit canonical constructor can do this:
Rank #2
public record ItemBatch(List<String> items) {
public ItemBatch {
items = List.copyOf(items);
}
}
The compact constructor assigns the normalized parameter back to items; the compiler then assigns that value to the component field. List.copyOf prevents changes through a caller-owned mutable list from changing the record’s contents. This is a shallow copy of the list, so mutable objects stored as list elements are not themselves copied.
How to validate or normalize record components
Use a compact constructor when validation or normalization applies to the incoming components. For example, this rejects a missing or blank identifier:
public record UserId(String value) {
public UserId {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException("value must not be blank");
}
}
}
The compact constructor validates the parameter before the compiler performs the component-field assignments. Use an explicit canonical constructor when you need to write those assignments yourself, such as when making a defensive copy of a mutable input:
public record ItemBatch(List<String> items) {
public ItemBatch(List<String> items) {
this.items = List.copyOf(items);
}
}
Constructors are not the only members you can customize: a record can also declare an accessor explicitly when its API needs a particular behavior. Keep such customization consistent with the record’s role as a transparent carrier of its components.
Rank #4
When to use a record instead of a conventional class
| Consideration | Record | Conventional class |
|---|---|---|
| State model | A fixed set of named components declared in the header. | Fields can be managed independently; the state model is not defined by a record header. |
| Boilerplate | Compiler supplies the canonical constructor, component accessors, and standard value methods. | You implement or generate the constructor, accessors, equality, hash code, and string form as needed. |
| Mutability | Component references are final; referenced mutable objects still need defensive handling. | You choose the fields’ mutability and any defensive-copy policy. |
| Inheritance | Implicitly final; cannot be extended, but can implement interfaces. | Can participate in class inheritance when not declared final, subject to Java’s class rules. |
| Customization | Supports compact or canonical constructors and explicitly declared members. | Supports the broader range of class design choices. |
| Interoperability | Has record-specific serialization and reflection behavior. | Uses ordinary class serialization and reflection behavior. |
Choose a record when the type’s identity is naturally its fixed component values and the generated value-oriented methods fit the API. A conventional class is a better fit when the object needs a mutable lifecycle, a class superclass, or state and behavior that should not be exposed as a fixed component list.
Record equality and hash codes are based on component values for records of the same type. Java’s record contract also requires the copy invariant: constructing a record from its accessors’ values must produce an equal record. For a record R, if R copy = new R(r.c1(), r.c2(), ..., r.cn()), then r.equals(copy) must be true (Oracle’s record documentation).
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
Can a record implement an interface or use type parameters?
Yes. A record may declare generic type parameters and implement interfaces. It cannot extend another class because every record is implicitly final and records already have their class inheritance fixed by the language.
public record Result<T>(T value, boolean successful) implements Serializable { }
This example uses a type parameter for the component type and implements an interface. Use interfaces for shared behavior or contracts when a record cannot inherit implementation from a class.
What happens when a record is serialized?
A record can implement Serializable, but its deserialization rules differ from those of ordinary serializable classes. Deserialization invokes the record’s canonical constructor, so constructor validation and normalization apply. Certain readObject and writeObject methods are ignored for records; do not rely on those hooks to customize record serialization.
Records also have a reflection API: Class.isRecord() tests whether a class is a record, and Class.getRecordComponents() returns information about its components. These APIs let frameworks and tools inspect the record’s declared data shape without treating it as an ordinary bean.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWhich Java version supports records?
Records first appeared as a preview feature in Java SE 14, were previewed again in Java SE 15, and became a permanent language feature in Java SE 16. This history is listed in Oracle’s Java language updates. If a project targets an earlier Java release, records are not available as a standard feature in that release; preview-feature use in the earlier versions required explicitly enabling preview features.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

