Records vs Classes

When to Use a Record

RecordRegular class
Purposecarry data (DTOs, results, keys, events)model behaviour with changing state
Fieldsfinal, fixed by the headeranything
Inheritancecannot extend a class; implicitly finalcan extend and be extended
Interfacescan implement interfacescan implement interfaces
equals/hashCode/toStringgeneratedwrite yourself
Good examplesOrderSummary, ApiError, map keysShoppingCart, BankAccount, JPA entities

Tip: JPA @Entity classes cannot be records (they need a no-arg constructor and mutable fields). Use records for request/response DTOs instead.

Records as Map Keys and Local Records

Example

Because records have value-based equals and hashCode, they are perfect composite keys. You can also declare a record inside a method.

import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        record CityDate(String city, int day) implements Comparable<CityDate> {
            public int compareTo(CityDate o) {
                int c = city.compareTo(o.city);
                return c != 0 ? c : Integer.compare(day, o.day);
            }
        }

        Map<CityDate, Integer> orders = new TreeMap<>();
        orders.merge(new CityDate("Delhi", 1), 120, Integer::sum);
        orders.merge(new CityDate("Agra", 2), 40, Integer::sum);
        orders.merge(new CityDate("Delhi", 1), 30, Integer::sum);
        orders.forEach((k, v) -> System.out.println(k + " -> " + v));
    }
}

Output

CityDate[city=Agra, day=2] -> 40
CityDate[city=Delhi, day=1] -> 150