DevNotes
Support
Core Java · Chapter 10

Records (Java 16+)

Compact, immutable data carriers with generated constructors, accessors, equals, hashCode and toString.

◷ 6 min read§ 28 sections? 10 interview questions{ } 25 code examples

#Introduction

One of the biggest additions to modern Java is the Record feature. Records were introduced as a preview in Java 14 and became a standard feature in Java 16.

A Record is a special type of class designed to represent immutable data with minimal boilerplate code. Instead of writing:

  • Fields
  • Constructor
  • Getters
  • equals()
  • hashCode()
  • toString()

Java generates them automatically.

Records are widely used for:

  • DTOs
  • API Request Objects
  • API Response Objects
  • Configuration Objects
  • Event Objects
  • Value Objects

#Why Were Records Introduced?

Before Records

Java
public class Employee {

    private final int id;
    private final String name;

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) { ... }

    @Override
    public int hashCode() { ... }

    @Override
    public String toString() { ... }
}

More than 40 lines of code.

Using a Record

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

Only one line.

#What is a Record?

A Record is a special immutable class whose primary purpose is to hold data.

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

Usage:

Java
Employee employee = new Employee(101, "John");

#What Does Java Generate Automatically?

For every Record, Java automatically generates:

  • Private final fields
  • Canonical constructor
  • Accessor methods
  • equals()
  • hashCode()
  • toString()

Internally,

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

behaves roughly like:

Java
public final class Employee {

    private final int id;
    private final String name;

    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int id() {
        return id;
    }

    public String name() {
        return name;
    }

    // equals()
    // hashCode()
    // toString()
}

#Creating a Record

Java
public record Student(int id, String name, double marks) {}

Creating an object:

Java
Student s = new Student(1, "Rahul", 95.5);

#Accessor Methods

Records do not generate getters like getId(). Instead, they generate id(), name() and marks().

Java
System.out.println(s.id());
System.out.println(s.name());
Output
1
Rahul

#Immutability

Records are immutable.

Wrong:

Java
employee.id = 200;   // Compilation Error

Wrong:

Java
employee.setId(200);   // No setter exists

State cannot be changed.

#Canonical Constructor

Java generates one automatically, and you can customize it.

Java
public record Employee(int id, String name) {

    public Employee {
        if (id <= 0) {
            throw new IllegalArgumentException("Invalid Id");
        }
    }

}

#Compact Constructor

The constructor shown above is called a Compact Constructor. Its purpose is validation.

Java
public record User(String username) {

    public User {
        Objects.requireNonNull(username);
    }

}

Useful for validating record components.

#Normal Constructor

You can also define additional constructors:

Java
public Employee(int id) {
    this(id, "Unknown");
}

It delegates to the canonical constructor.

#Custom Methods

Records can contain methods.

Java
public record Rectangle(int length, int width) {

    public int area() {
        return length * width;
    }
}

Usage:

Java
Rectangle r = new Rectangle(10, 20);
System.out.println(r.area());
Output
200

#Static Members

Records support static fields and methods.

Java
public record Employee(int id, String name) {

    static String company = "OpenAI";

}

#Records Can Implement Interfaces

Java
interface Printable {
    void print();
}

public record Employee(int id, String name) implements Printable {

    @Override
    public void print() {
        System.out.println(name);
    }

}

#Records Cannot Extend Classes

Wrong:

Java
public record Employee(int id) extends Person {   // Compilation Error
}

Reason: Records already extend java.lang.Record.

#Nested Records

Records can be nested.

Java
public class Order {

    public record Item(int id, String name) {}

}

#Reflection

Java
Employee.class.isRecord();
Output
true

Useful in frameworks.

#Record Components

Java
record Employee(int id, String name) {}

Components: id, name. Retrieve them with:

Java
Employee.class.getRecordComponents();

#Record vs Class

FeatureRecordClass
ImmutableYesOptional
BoilerplateVery LowHigh
SettersNoYes
InheritanceCannot extend classSupported
equals() / hashCode()GeneratedManual
toString()GeneratedManual

#Record vs Lombok

  • Lombok @Data — generates mutable objects.
  • Record — automatically creates immutable objects.

#Records in Spring Boot

Typical DTO:

Java
public record LoginRequest(
        String username,
        String password
) {}

Controller:

Java
@PostMapping("/login")
public void login(@RequestBody LoginRequest request) {
}

Very common in Spring Boot 3.x.

#Records with JSON

Libraries like Jackson support Records.

JSON
{
    "id": 101,
    "name": "John"
}

This automatically maps to Employee employee; without setters.

#Real Project Examples

AreaRecords
DTOEmployeeResponse
REST APILoginRequest, RegisterRequest, PaymentResponse
KafkaOrderEvent, PaymentEvent, UserEvent
ConfigurationDatabaseConfig

#Interview Questions

Q1What is a Record?

A special immutable class designed for holding data.

Q2Which Java version introduced Records?

Preview in Java 14. Standard in Java 16.

Q3Are Records immutable?

Yes. Their components are final.

Q4Can Records extend another class?

No. They already extend java.lang.Record.

Q5Can Records implement interfaces?

Yes.

Q6Can Records have constructors?

Yes — canonical, compact, and additional constructors.

Q7Can Records contain methods?

Yes. Business methods are allowed.

Q8Can Records contain static members?

Yes.

Q9Are getters generated?

Yes, but as accessor methods like id() and name(), not getId().

Q10When should we use Records?

When creating immutable data carriers such as DTOs, request/response models, configuration objects, and event classes.

#Common Mistakes

  • Trying to add setters.
  • Using Records for JPA entities.
  • Extending another class.
  • Assuming accessor methods are named getX().

#Best Practices

  • Use Records for immutable DTOs.
  • Keep business logic minimal.
  • Validate inputs using compact constructors.
  • Use Records with REST APIs and messaging.
  • Avoid using Records as mutable domain entities.

#Quick Revision

Record
Immutable
Auto Constructor
Accessor Methods
equals() · hashCode() · toString()
Used for
DTO
REST API
Events

#Interview Cheat Sheet

RequirementRecommendation
Immutable DTORecord
JPA EntityClass
Request/ResponseRecord
Event ObjectRecord
ValidationCompact Constructor
Additional BehaviourCustom Methods

#Chapter Summary

After completing this chapter, you should be able to:

  • Explain what Records are and why they were introduced.
  • Create immutable data classes using Records.
  • Use canonical and compact constructors.
  • Understand automatically generated methods.
  • Compare Records with traditional classes and Lombok.
  • Use Records effectively in Spring Boot applications.
  • Confidently answer modern Java interview questions related to Records.