Java Tutorial 0/145 lessons ~6 min read Lesson 35

    Java Records

    java records immutable DTO compact constructor accessor methods POJO Spring Boot Java 16

    Course progress0%
    Focus
    30 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Learning Objectives

    After completing this lesson, you will be able to:

    • Understand what Records are
    • Learn why Records were introduced
    • Compare Records with traditional POJOs
    • Create immutable data classes using Records
    • Use Constructors in Records
    • Add Methods to Records
    • Use Compact Constructors
    • Understand Record Internals
    • Use Records with Collections and Streams
    • Use Records in Spring Boot Applications
    • Learn Best Practices
    • Prepare for Java Interview Questions

    Introduction

    One of the biggest problems in Java before Java 16 was writing boilerplate code.

    Consider a simple Employee class.

    code
    public class Employee {
    private final int id;
    private final String name;
    private final double salary;
    public Employee(int id,
    String name,
    double salary){
    this.id = id;
    this.name = name;
    this.salary = salary;
    }
    public int getId(){
    return id;
    }
    public String getName(){
    return name;
    }
    public double getSalary(){
    return salary;
    }
    @Override
    public boolean equals(Object obj){
    ...
    }
    @Override
    public int hashCode(){
    ...
    }
    @Override
    public String toString(){
    ...
    }
    }

    Almost 80% of the code is boilerplate.

    Java 16 introduced Records to solve this problem.

    A Record automatically generates:

    • Constructor
    • Getters (Accessor Methods)
    • equals()
    • hashCode()
    • toString()

    Records are ideal for immutable data carriers such as DTOs, API responses, configuration objects, and value objects.

    Why Records?

    Without Records

    code
    public class User {
    private final String username;
    private final String email;
    // Constructor
    // Getters
    // equals()
    // hashCode()
    // toString()
    }

    With Records

    code
    public record User(
    String username,
    String email
    ){ }

    That's all.

    Benefits

    • Less Code
    • Immutable
    • Thread Safe
    • Better Readability
    • Cleaner APIs

    What is a Record?

    A Record is a special kind of class designed to model immutable data.

    Syntax

    code
    public record Employee(
    int id,
    String name,
    double salary
    ){
    }

    Creating Record Objects

    code
    Employee employee =
    new Employee(
    101,
    "Rahul",
    75000
    );
    System.out.println(employee);

    Output

    code
    Employee[id=101,
    name=Rahul,
    salary=75000.0]

    Accessor Methods

    Records automatically generate accessor methods.

    code
    Employee employee =
    new Employee(
    101,
    "John",
    90000
    );
    System.out.println(
    employee.id()
    );
    System.out.println(
    employee.name()
    );
    System.out.println(
    employee.salary()
    );

    Output

    code
    101
    John
    90000.0

    Notice:

    Accessor methods are:

    code
    employee.id()

    NOT

    code
    employee.getId()

    Auto Generated Methods

    Java automatically generates

    • Constructor
    • Accessor Methods
    • equals()
    • hashCode()
    • toString()

    Equivalent Class

    code
    Employee Record
    Compiler
    Immutable Java Class

    equals()

    code
    Employee e1 =
    new Employee(
    1,
    "Amit",
    50000
    );
    Employee e2 =
    new Employee(
    1,
    "Amit",
    50000
    );
    System.out.println(
    e1.equals(e2)
    );

    Output

    code
    true

    hashCode()

    Automatically generated.

    code
    System.out.println(
    employee.hashCode()
    );

    toString()

    Automatically generated.

    code
    System.out.println(
    employee
    );

    Output

    code
    Employee[id=101,
    name=Amit,
    salary=50000]

    Custom Constructor

    Records support constructors.

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

    Compact Constructor

    Preferred approach.

    code
    public record Employee(
    int id,
    String name){
    public Employee{
    if(id <= 0){
    throw new IllegalArgumentException(
    "Invalid ID"
    );
    }
    }
    }

    The compiler automatically assigns fields after validation.

    Adding Methods

    Records can contain methods.

    code
    public record Employee(
    int id,
    String name){
    public String greeting(){
    return "Welcome " + name;
    }
    }

    Usage

    code
    System.out.println(
    employee.greeting()
    );

    Static Members

    Records support static fields and methods.

    code
    public record User(
    String username){
    public static String company(){
    return "TechLearningPro";
    }
    }

    Nested Records

    code
    public class Company{
    public record Employee(
    int id,
    String name){
    }
    }

    Record with Collections

    code
    public record Department(
    String name,
    List<Employee> employees){
    }

    For deep immutability, use immutable collection implementations or defensive copies.

    Records with Streams

    code
    employees.stream()
    .filter(
    e -> e.salary() > 80000
    )
    .forEach(System.out::println);

    Record Internals

    Compiler

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

    Conceptually becomes

    code
    final class Employee
    extends Record

    Properties

    • Final Class
    • Final Fields
    • Immutable
    • Cannot Extend Another Class

    Record Memory Diagram

    code
    JVM Heap
    Employee Record
    ┌──────────────┐
    │ id = 101 │
    │ name = Rahul │
    └──────────────┘

    Record Restrictions

    Records can:

    • Implement interfaces
    • Have methods
    • Have constructors
    • Have static members

    Records cannot:

    • Extend another class
    • Declare mutable instance fields
    • Add extra instance variables outside the record components

    Record vs POJO

    RecordPOJO
    ImmutableMutable
    Less BoilerplateMore Boilerplate
    Auto-generated MethodsManual Methods
    FinalUsually Non-final
    Better for DTOBetter for Rich Domain Models

    Real-World Example: API Response

    code
    public record ApiResponse(
    int status,
    String message){
    }

    Real-World Example: Spring Boot DTO

    code
    public record EmployeeDTO(
    Long id,
    String name,
    String department){
    }

    Spring Boot 3 fully supports Records for request and response DTOs.

    Real-World Example: Configuration

    code
    public record DatabaseConfig(
    String url,
    String username,
    String password){
    }

    Best Practices

    Use Records for DTOs

    Ideal for:

    • REST Responses
    • Request Objects
    • Events
    • Configuration
    • Value Objects

    Keep Records Immutable

    Avoid mutable objects inside records when possible.

    Use Compact Constructors

    Validate inputs without repeating assignments.

    Prefer Records for Read-Only Data

    If objects should not change after creation, Records are an excellent choice.

    Use with Streams

    Records integrate naturally with Streams and functional programming.

    Common Mistakes

    Trying to Modify Fields

    Wrong

    code
    employee.name = "Rahul";

    Records are immutable.

    Using Getters

    Wrong

    code
    employee.getName();

    Correct

    code
    employee.name();

    Extending a Record

    Wrong

    code
    class Manager extends Employee

    Records are implicitly final.

    Using Records for JPA Entities

    Avoid using Records as JPA entities because most JPA providers require mutable entities, a no-argument constructor, and proxy support.

    Use Records for DTOs instead.

    Assuming Deep Immutability

    A record's fields are final, but if a field references a mutable object (for example, a List), the contents can still change unless you create immutable copies.

    Hands-on Exercise

    Create a Java program that:

    1. Creates a Student record.
    2. Creates an EmployeeDTO record.
    3. Uses accessor methods.
    4. Demonstrates equals().
    5. Demonstrates hashCode().
    6. Creates a compact constructor for validation.
    7. Adds a custom method.
    8. Uses records with Streams.
    9. Uses records inside a Spring Boot REST response.
    10. Demonstrates nested records.

    Summary

    Records, introduced in Java 16, provide a concise and immutable way to model data. They eliminate boilerplate by automatically generating constructors, accessors, equals(), hashCode(), and toString(). Records are ideal for DTOs, API models, configuration objects, and value objects, and they integrate seamlessly with Streams, Lambdas, and Spring Boot. They are not intended to replace every class but are an excellent choice for immutable data carriers.

    Key Takeaways

    • Records are immutable data carriers.
    • Records dramatically reduce boilerplate code.
    • The compiler generates constructors, accessors, equals(), hashCode(), and toString().
    • Accessor methods use the component name (for example, name()), not JavaBean getters.
    • Compact constructors are ideal for validation.
    • Records can implement interfaces but cannot extend classes.
    • Records are implicitly final.
    • Prefer Records for DTOs and API models.
    • Avoid using Records as JPA entities.
    • Records work well with Streams, Lambdas, and modern Spring Boot applications.

    Professional Interview Questions

    1What are Records in Java?

    Professional Answer

    Records are a special kind of class introduced in Java 16 to model immutable data. They automatically generate constructors, accessor methods, equals(), hashCode(), and toString(), significantly reducing boilerplate code. Records are best suited for data transfer objects (DTOs), configuration classes, and other immutable value objects.

    Follow-up Questions

    • Which Java version introduced Records?
    • Can Records have constructors and methods?
    • Are Records immutable?

    Interview Tip: Record = Immutable Data Class + Auto-Generated Methods.

    2What is the difference between a Record and a POJO?

    Professional Answer

    A POJO is a regular Java class that can be mutable or immutable and typically requires manually writing constructors, getters, equals(), hashCode(), and toString(). A Record is a specialized, immutable data class that automatically generates these members, making it ideal for simple data carriers while reducing boilerplate.

    Follow-up Questions

    • When should you choose a Record?
    • Can a Record replace every POJO?

    Interview Tip: POJO → General-Purpose Class, Record → Immutable Data Carrier.

    3Can Records be used as JPA Entities?

    Professional Answer

    In most cases, no. JPA entities are typically mutable, require a no-argument constructor, and rely on proxy-based mechanisms for lazy loading. Records are immutable, final, and lack a no-argument constructor by default, making them unsuitable as JPA entities. However, Records are an excellent choice for DTO projections, REST request/response models, and read-only views.

    Follow-up Questions

    • What should you use Records for in Spring Boot?
    • Why do JPA providers require mutable entities?

    Interview Tip: JPA Entity → Regular Class, DTO / API Response → Record.

    Ready to mark this lesson complete?Track your journey across the entire course.