Codectionary / Developer documentation / Java

Records

Introduced as a standard feature in Java 16, a record is a compact way to declare an immutable data-carrier class. Writing 'record Point(int x, int y) {}' automatically generates a constructor, private final fields, public accessor methods, plus equals(), hashCode(), and toString() - all the boilerplate that would otherwise need to be written by hand for a simple immutable class.

Syntax

record RecordName(type field1, type field2) { }

Examples

Basic Record

A record automatically gets a constructor, accessors, equals, hashCode, and toString.

public record Point(int x, int y) { }

public class RecordExample {
    public static void main(String[] args) {
        Point p1 = new Point(3, 4);

        System.out.println(p1.x());          // 3 - auto-generated accessor
        System.out.println(p1.y());          // 4
        System.out.println(p1);               // Point[x=3, y=4] - auto toString()

        Point p2 = new Point(3, 4);
        System.out.println(p1.equals(p2));    // true - auto equals() compares fields
    }
}

Record with Additional Methods

Records can still define their own methods alongside the automatically generated ones.

public record Rectangle(double width, double height) {
    public double area() {
        return width * height;
    }

    public boolean isSquare() {
        return width == height;
    }
}

Rectangle r = new Rectangle(5, 5);
System.out.println(r.area());       // 25.0
System.out.println(r.isSquare());   // true

Compact Constructor for Validation

Records support a compact constructor syntax for validating fields at creation time.

public record Temperature(double celsius) {
    public Temperature {  // compact constructor - no parameter list repeated
        if (celsius < -273.15) {
            throw new IllegalArgumentException("Below absolute zero!");
        }
    }

    public double toFahrenheit() {
        return celsius * 9 / 5 + 32;
    }
}

Temperature t = new Temperature(25);
System.out.println(t.toFahrenheit());  // 77.0

// new Temperature(-300);  // throws IllegalArgumentException

Best practices

  • Use records for simple, immutable data carriers (DTOs, value objects) instead of hand-writing a full class with getters, equals, hashCode, and toString
  • Add validation logic in a compact constructor to guarantee a record can never be created in an invalid state
  • Remember records are implicitly final and all fields are final - they are not meant for classes that need mutable state or inheritance
  • Use a record's auto-generated accessor methods (x(), y()) rather than adding your own getX()/getY() unless you specifically need JavaBean-style naming

Runtime & versions

Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

Java Language Specification

Specifications & further reading