BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ OOP and types

Java language

Records

A record is a compact class for plain data: you list the fields once and Java generates the constructor, getters, equals, hashCode and toString.

๐Ÿ”Ž Unravel this example

At a glance

Mental model

A labelled form with fixed boxes.

What happens, in order
  1. 1record Point(int x, int y) {} creates a final class with private final fields, a constructor, accessors x() and y(), and value-based equals, hashCode and toString
  2. 2A compact constructor lets you validate: Point { if (x < 0) throw new IllegalArgumentException(); }
  3. 3Records can have static methods, extra methods and implement interfaces, but cannot extend a class or add instance fields
  4. 4Because equals and hashCode compare all components, records work well as keys in a Map or elements of a Set, and as the immutable messages passed between threads or sent over Kafka
  5. 5Since Java 21 a record can be taken apart in a pattern: if (obj instanceof Point(int x, int y)) { ..} or in a switch, giving you the components as variables without calling the accessors.
Remember
Watch out
Assuming deep immutabilityUsing a record as a JPA entity
Example (highlighted lines explain it)
public record Money(BigDecimal amount, String currency) {    public Money {        if (amount.signum() < 0) {            throw new IllegalArgumentException("negative amount");        }    }    public Money plus(Money other) {        return new Money(amount.add(other.amount), currency);    }}
Read the full explanation (about 1 min)

A record is a compact class for plain data: you list the fields once and Java generates the constructor, getters, equals, hashCode and toString.

A mental model

A labelled form with fixed boxes. Once filled in, it cannot be edited, and two forms with identical contents are considered equal.

How it works

record Point(int x, int y) {} creates a final class with private final fields, a constructor, accessors x() and y(), and value-based equals, hashCode and toString.

A compact constructor lets you validate: Point { if (x < 0) throw new IllegalArgumentException(); }.

Records can have static methods, extra methods and implement interfaces, but cannot extend a class or add instance fields.

Because equals and hashCode compare all components, records work well as keys in a Map or elements of a Set, and as the immutable messages passed between threads or sent over Kafka.

Since Java 21 a record can be taken apart in a pattern: if (obj instanceof Point(int x, int y)) { ... } or in a switch, giving you the components as variables without calling the accessors.

Going deeper

Records are shallowly immutable: a record holding a List still lets the list change unless you copy it with List.copyOf in the constructor. They suit DTOs, API responses, map keys and messages, but not JPA entities.

Under the hood

The compiler generates the members, and equals, hashCode and toString are implemented with invokedynamic (ObjectMethods). The class extends java.lang.Record.

Common mistakes

  • Assuming deep immutability.
  • Using a record as a JPA entity.

How Unravel recognises it

When you paste code, Unravel looks for these signs of records. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Builds on this

Frequently asked questions

What is Records?

A record is a compact class for plain data: you list the fields once and Java generates the constructor, getters, equals, hashCode and toString.

What are the most common mistakes with Records?

Assuming deep immutability. Using a record as a JPA entity.

How can I see Records in real code?

Paste your own Java into Unravel and it will point out where records appears, explain how it works at the detail level you choose, and draw the flow of the code around it.