W Javie 14 zawitał do nas bardzo ciekawy feature o nazwie „records”. W Javie 15 jest w fazie „second preview”, czyli zbliża się do finalnego wydania. O co więc w recordach chodzi?
Czy poniższy kod wydaję Ci się znajomy? (jest to wycinek z kursu – Kompletna aplikacja w języku Java – od zera do installera):
package pl.clockworkjava.domain.room.dto; public class RoomDTO { private long id; private int number; private String beds; private int bedsCount; private int roomSize; public RoomDTO(long id, int number, String beds, int bedsCount, int roomSize) { this.id = id; this.number = number; this.beds = beds; this.bedsCount = bedsCount; this.roomSize = roomSize; } public long getId() { return id; } public int getNumber() { return number; } public String getBeds() { return beds; } public int getBedsCount() { return bedsCount; } public int getRoomSize() { return roomSize; } //+equals, +hashcode }
Czyli typowa klasa służąca tylko i wyłącznie do opakowania danych i wysłania gdzieś w świat albo inną część systemu. Każdy większy program w Javie ma takich klas kilka(naście/set). Przydają się. Dzięki DTO konkretnie możemy odciąć obiekty domenowe od frontendu/odpowiedzi RESTowych (bo obiekt domenowy może mieć wiele danych i metod, które nie chcemy, by poza jego „podwórko” wychodziły).
Użycie klasy RoomDTO może wyglądać tak (losowe operacje):
RoomDTO dto = new RoomDTO(1, 23, "Podwójne", 1, 2); String bedsInfo = dto.getBeds(); RoomDTO dto2 = new RoomDTO(1, 23, "Podwójne", 1, 2); if(dto.equals(dto2)) { System.out.println("Weird..."); }
Funkcjonalność rekordu pozwala nam na sprowadzenie nam definicje RoomDTO do kilku tylko linijek.
public record RoomDTO( long id, int number, String beds, int bedsCount, int roomSize ) { }
Powyższy kod wygeneruję nam klasę RoomDTO, wraz z konstruktorem przyjmującym cały zestaw parametrów zdefiniowanych pomiędzy ( ) przy deklarowaniu recordu. Dodatkowo wygeneruję nam się toString, hashCode, equals
oraz gettery. Haczyk jest taki, że gettery nie będą w standardowym formacie .getRoomSize()
, tylko .roomSize()
, więc przed przejściem na recordy trzeba będzie zrefactorować użycie getterów danej klasy (w czym IDE pomoże wielce).
Kod użycia record przedstawia się następująco, tylko jedna zmiana w porównaniu do originału:
RoomDTO dto = new RoomDTO(1, 23, "Podwójne", 1, 2); String bedsInfo = dto.beds(); RoomDTO dto2 = new RoomDTO(1, 23, "Podwójne", 1, 2); if(dto.equals(dto2)) { System.out.println("Weird..."); }
Dodatkowo rekordy mogą posiadać statyczne zmienne i metody oraz metody operujące na zdefiniowanym stanie.
public record RoomDTO( long id, int number, String beds, int bedsCount, int roomSize ) { public static int roomCount; public static void increaseCount() { roomCount++; } public String toJson() { String json = "{\"id\":%d, \"number\":%d, \"beds\":\"%s\"}"; return String.format(json, id, number, beds); } }
RoomDTO dto = new RoomDTO(1, 23, "Podwójne", 1, 2); String bedsInfo = dto.beds(); RoomDTO dto2 = new RoomDTO(1, 23, "Podwójne", 1, 2); if(dto.equals(dto2)) { System.out.println("Weird..."); System.out.println(dto.toJson()); }
Kolejnym udogodnieniem record jest możliwość dodawania własnych konstruktorów, warz z nadpisaniem konstruktora „głównego’ (z kompletem wartości), tak długo jak długo inicjalizowane są wszystkie pola rekordu.
Record nie może jednak rozszerzać lub implementować czegokolwiek, mają to być proste struktury danych.
By być na bieżąco i mieć realny wpływ na tematykę tworzonych przeze mnie artykułów zapraszam do dołączenia do mojego newslettera.