Record în Java

Clasa Record Java 16

Clasa de bază a tuturor tipurilor record: le dă equals, hashCode și toString după componente.

Sintaxă
public abstract class java.lang.Record

record Punct(int x, int y) { }   // extinde automat Record
boolean Class.isRecord()
RecordComponent[] Class.getRecordComponents()

Ce face Record

Orice record (de exemplu record Elev(String nume, int nota)) extinde automat clasa abstractă java.lang.Record, la fel cum orice clasă obișnuită extinde Object. Nu poți scrie extends Record de mână; compilatorul nu permite.

Record declară equals, hashCode și toString ca abstracte, iar compilatorul le generează pentru fiecare record după componente: două record-uri sunt egale dacă au toate componentele egale, iar toString arată Elev[nume=Ana, nota=9].

Poți scrie metode care primesc orice record cu tipul Record, sau verifica obiect instanceof Record. Prin reflecție, getClass().isRecord() și getRecordComponents() dau numele și valorile componentelor, ceea ce bibliotecile JSON folosesc pentru a transforma record-urile automat.

Ce returnează

Nu creezi direct obiecte Record; folosești tipurile record declarate de tine.

Exemple

Exemplul 1: Orice record este un Record

public class Main {
    record Elev(String nume, int nota) { }
    record Oras(String nume, String judet) { }

    static String descrie(Object o) {
        return o instanceof Record ? "record: " + o : "obiect obișnuit: " + o;
    }

    public static void main(String[] args) {
        System.out.println(descrie(new Elev("Ana", 9)));
        System.out.println(descrie(new Oras("Iași", "IS")));
        System.out.println(descrie("text"));
        System.out.println("Clasa de bază: " + Elev.class.getSuperclass().getName());
    }
}

Rezultat

record: Elev[nume=Ana, nota=9]
record: Oras[nume=Iași, judet=IS]
obiect obișnuit: text
Clasa de bază: java.lang.Record

Exemplul 2: equals și hashCode generate

import java.util.HashSet;
import java.util.Set;

public class Main {
    record Nota(String elev, String materie, int valoare) { }

    public static void main(String[] args) {
        Nota a = new Nota("Ana", "mate", 9);
        Nota b = new Nota("Ana", "mate", 9);
        Nota c = new Nota("Ana", "fizică", 9);
        System.out.println("a.equals(b): " + a.equals(b) + ", a == b: " + (a == b));
        System.out.println("a.equals(c): " + a.equals(c));
        System.out.println("hashCode egal: " + (a.hashCode() == b.hashCode()));
        Set<Nota> note = new HashSet<>(Set.of(a, c));
        note.add(b);
        System.out.println("Note distincte: " + note.size());
    }
}

Rezultat

a.equals(b): true, a == b: false
a.equals(c): false
hashCode egal: true
Note distincte: 2

Exemplul 3: Componentele citite prin reflecție

Metoda afiseaza funcționează pentru orice record, fără să-i cunoască tipul.

import java.lang.reflect.RecordComponent;

public class Main {
    record Produs(String nume, double pret, int stoc) { }

    static void afiseaza(Record r) throws ReflectiveOperationException {
        System.out.println(r.getClass().getSimpleName() + " (isRecord: " + r.getClass().isRecord() + ")");
        for (RecordComponent c : r.getClass().getRecordComponents()) {
            System.out.println("  " + c.getName() + " : " + c.getType().getSimpleName() + " = " + c.getAccessor().invoke(r));
        }
    }

    public static void main(String[] args) throws ReflectiveOperationException {
        afiseaza(new Produs("Caiet A4", 7.5, 128));
    }
}

Rezultat

Produs (isRecord: true)
  nume : String = Caiet A4
  pret : double = 7.5
  stoc : int = 128

Greșeli frecvente

  • Încerci class Elev extends Record. Nu compilează; folosește cuvântul cheie record.
  • Pui într-un record un tablou sau o listă modificabilă și te aștepți ca equals să compare conținutul tabloului. Pentru tablouri, equals compară referințele; folosește List.of sau scrie singur equals.

Comenzi înrudite

  • IllegalArgumentException: Excepția aruncată când o metodă primește un argument cu valoare nepermisă (vârstă negativă, lună 13).
  • Object.equals: equals() spune dacă două obiecte sunt „egale”, iar hashCode() dă un număr folosit de HashMap și HashSet; se suprascriu împreună.