Java Records

Java Programming Tutorials

Java Object Oriented

Java records provide a concise way to model data whose meaning comes from a fixed set of values. A record declaration creates a special final class with component fields, accessors, a canonical constructor, and value-based equals(), hashCode(), and toString() methods.

Records became a permanent Java feature in Java 16. They are useful for request values, coordinates, configuration entries, query results, and messages that primarily carry data.

Declare and Use a Record

List the record components in the header. Java creates an accessor with the component name, not a JavaBean-style get prefix.

Example:

public record Employee(int id, String name, String department) { }

Employee employee = new Employee(101, "Aarav", "Engineering");

// Access components through generated methods.
System.out.println(employee.name());
System.out.println(employee);

Members Generated by a Record

Generated member Purpose
Private final component field Stores each value from the header
Public component accessor Returns the corresponding value
Canonical constructor Accepts every component in header order
equals() and hashCode() Provide component-based value equality
toString() Displays the record name and component values

Records Use Value Equality

Two instances of the same record class compare equal when their corresponding components compare equal. This makes records suitable as map keys and set elements when their component values are also stable and have correct equality behavior.

record Point(int x, int y) { }

Point first = new Point(4, 7);
Point second = new Point(4, 7);

// The generated equality compares component values.
System.out.println(first.equals(second)); // true
System.out.println(first.hashCode() == second.hashCode()); // true

Validate with a Compact Constructor

A compact canonical constructor omits the parameter list. Use it to validate or normalize values before Java assigns them to the final component fields.

public record Product(String name, double price) {
    public Product {
        // Reject invalid state before the record is created.
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("Name is required");
        }
        if (price < 0) {
            throw new IllegalArgumentException("Price cannot be negative");
        }
        name = name.trim();
    }
}

Do not assign directly to the component fields in a compact constructor. Adjust the parameter variables when normalization is required.

Add an Alternative Constructor

An additional constructor must delegate to the canonical constructor as its first action. This keeps all record creation on the same initialization path.

public record Money(String currency, long minorUnits) {
    public Money(long minorUnits) {
        // Delegate to the canonical constructor.
        this("INR", minorUnits);
    }
}

Add Methods and Static Members

A record can declare instance methods, static fields, static methods, and implement interfaces. It cannot declare extra instance fields because its state must be described by the record header.

public record Rectangle(double width, double height) {
    public double area() {
        // Instance methods can use record components directly.
        return width * height;
    }

    public static Rectangle square(double side) {
        return new Rectangle(side, side);
    }
}

Records Are Shallowly Immutable

The component fields are final, so a record cannot replace a component after construction. The object referenced by a component may still be mutable. Make a defensive copy when the record must protect a collection or array.

import java.util.List;

public record Team(String name, List<String> members) {
    public Team {
        // Store an unmodifiable copy instead of the caller's list.
        members = List.copyOf(members);
    }
}

A final reference is not the same as a deeply immutable value. Review every mutable component and copy it at the boundary when required.

Use Generic and Local Records

Records can have type parameters. You can also declare a local record inside a method to give a temporary calculation a clear named structure.

public record Pair<L, R>(L left, R right) { }

static void printTotals() {
    // This type is available only inside the method.
    record DepartmentTotal(String department, double total) { }
    DepartmentTotal result = new DepartmentTotal("Sales", 84500.0);
    System.out.println(result);
}

Implement Interfaces

A record cannot extend another class because every record already extends java.lang.Record. It can implement one or more interfaces.

interface Identified {
    long id();
}

public record Order(long id, double total) implements Identified {
    // The generated id() accessor satisfies the interface method.
}

Use Record Patterns in Modern Java

Java 21 finalized record patterns. They let you test a record type and extract its components in one operation, including nested records.

record Point(int x, int y) { }
record Line(Point start, Point end) { }

static void printStart(Object value) {
    if (value instanceof Line(Point(var x, var y), Point end)) {
        // x and y come from the nested start record.
        System.out.println(x + ", " + y);
    }
}

When to Use a Record

  • Use a record when a fixed collection of values defines the object's public meaning.
  • Use a normal class when identity, mutable state, framework proxies, or hidden representation matters.
  • Avoid exposing sensitive components because the generated accessors and toString() reflect the declared state.
  • Check framework requirements before replacing entity classes with records.

Conclusion

Java records remove repetitive data-carrier code while preserving nominal types, validation, interfaces, methods, and useful value equality. Treat their components as the complete state description, protect mutable values with defensive copies, and use a regular class when the model needs identity or evolving hidden state.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram