programowanieProgramista Java

Co to jest klasa record w Javie, do czego służy i jakie ma ograniczenia?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania:

Klasy record (record) pojawiły się w Javie 14 jako podgląd, a od wydania Javy 16 są stabilną funkcjonalnością. Realizują koncepcję niemutowalnych (immutable) kontenerów do przechowywania danych, podobnych do obiektów wartości (value-objects). Jest to odpowiedź na rozwlekłość klasycznych DTO i POJO w Javie.

Problem:

Dla prostych obiektów z danymi trzeba było ręcznie implementować konstruktory, equals(), hashCode(), toString(). To rutynowa, podatna na błędy praca, zajmująca wiele linii kodu.

Rozwiązanie:

Klasa record jest deklarowana w jednej linii i automatycznie otrzymuje konstruktor, gettery, equals(), hashCode(), toString(). Pola record są niemutowalne (final), rekordy są szczególnie przydatne do przesyłania informacji między warstwami aplikacji.

Przykład kodu:

public record Point(int x, int y) {} Point p = new Point(3, 5); System.out.println(p.x()); // 3 System.out.println(p); // Point[x=3, y=5]

Kluczowe cechy:

  • Niemutowalność: pola final, wartości można ustawiać tylko przez konstruktor.
  • Automatyczne generowanie standardowych metod.
  • Nie mogą dziedziczyć od innych klas (oprócz Object); mogą implementować interfejsy.

Pytania z pułapką.

Czy można zmienić stan obiektu record po jego utworzeniu?

Nie — wszystkie pola są final, nie można zmienić wartości w żaden sposób.

Czy można tworzyć recordy z nietypową logiką w konstruktorze?

Tak, można zdefiniować konstruktor kompaktowy lub standardowy i dodać sprawdzenia:

public record Point(int x, int y) { public Point { if (x < 0 || y < 0) throw new IllegalArgumentException(); } }

Czy record może być abstrakcyjny lub dziedziczyć pola/logikę od innych klas?

Nie — record zawsze jest finalny. Może implementować interfejsy, ale nie może dziedziczyć klas, poza Object.

Typowe błędy i antywzorce

  • Próba uczynienia pól zmiennymi — składnia na to nie pozwoli.
  • Tworzenie złożonej logiki wewnątrz record, łamiąc ideę prostych „kontenerów danych”.
  • Użycie rekordów tam, gdzie potrzebna jest zwykła klasa z zachowaniem.

Przykład z życia

Negatywny przypadek

Użycie długich POJO dla każdego zapytania/odpowiedzi, z ręcznym pisaniem equals, hashCode, toString, konstruktorów i getterów.

Zalety:

  • Pełna elastyczność realizacji.

Wady:

  • Dużo kodu.
  • Wysokie ryzyko popełnienia błędu.

Pozytywny przypadek

Przeniesienie wszystkich DTO do klas record:

public record UserDTO(String login, String email) {}

Zalety:

  • Minimalna ilość kodu.
  • Automatycznie poprawny equals/hashCode.
  • Trudno popełnić błąd w realizacji.

Wady:

  • Jeśli potrzebny jest obiekt zmienny lub specyficzna logika — record się nie nada.