
Java programátor expert
Java bola v minulosti často kritizovaná za to, že treba napísať množstvo kódu, aby program začal niečo robiť. Najväčšie sťažnosti boli smerované k dátovým triedam. V Oracle si toho boli vedomí a začali pracovať na tom, aby Java okrem robustnosti a výrečnosti nadobudla aj atribúty stručnosti a priateľskosti k vývojárom. Vo verzii Java 14 [JEP-359] si autori nachystali ukážku toho, ako by sa dali takéto dátové triedy implementovať a po zapracovaní spätnej väzby od Java komunity priniesli nové rozšírenie jazyka Java vo verzii Java 16 [JEP-395] – Java Records.
Podobne ako Enum, Record je tiež špeciálny typ triedy v Jave. Records (záznamy) sú určené na zjednodušenie vytvárania nemenných dátových objektov, často označovaných aj ako dátové nosiče. Hlavný rozdiel medzi klasickou triedou a záznamom je v tom, že záznam sa snaží odstrániť celý sprievodný kód, ktorý je potrebný napísať pri nastavení dát alebo pri ich získavaní v inštancii triedy. Java záznam túto zodpovednosť deleguje na Java kompilátor, ktorý automaticky poskytuje stručné implementácie bežných metód ako sú: konštruktor, prístup k členom triedy (getter metódy), hashCode(), equals() a toString() metóda.
V skratke povedané, táto významná funkcionalita Java records priniesla možnosť stručnejšie definovať nemeniteľné (immutable) dáta, pričom pomáha znížiť množstvo opakujúceho sa kódu, a tak sa vývojári môžu sústrediť hlavne na programovanie biznis logiky.
Najlepšie pochopíme prínos tohto vylepšenia na príklade. Pozrime sa teraz spolu na to, ako by sme zadefinovali dátový agregát bez Java Record a s ním. Vytvorme si jednoduchú dátovú triedu kniha, s atribútmi názov a cena.
V tomto príklade, aj keď trieda Book obsahuje len dve polia (name a price), je potrebné zapísať veľa opakujúceho sa kódu (konštruktor, gettery, toString(), equals(), a hashCode()) na zabezpečenie správneho fungovania objektu.
import java.util.Objects;
public class Book {
private final String name;
private final double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
@Override
public String toString() {
return "Book {name = '" + name + "', price = " + price + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
return Double.compare(book.price, price) == 0 && name.equals(book.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
}
So zavedením kľúčového slova record, rovnaká dátová trieda môže byť zadefinovaná oveľa stručnejšie.
public record Book(String name, double price) {}
Táto jedna riadková deklarácia robí v podstate nasledovné:
Ak sa pozrieme na byte-kód môžeme si všimnúť niekoľko detailov:
Použitie v triede Main je podobné na aké sme zvyknutí z používania klasických JavaBean tried. Musíme sa však odnaučiť používať getter metódy, keďže tieto record trieda neobsahuje.
public class Main {
public static void main(String[] args) {
Book book1 = new Book("Effective Java", 47.38);
System.out.println(book1.name());
System.out.println(book1.price());
System.out.println(book1);
Book book2 = new Book("Effective Java", 47.38);
System.out.println(book1.equals(book2));
}
}
Výstup tohto programu je nasledovný:
Na predchádzajúcom príklade sme videli ako definovaním záznamovej triedy pomocou jedného riadku, sme dokázali jednoducho implementovať jednoduchú dátovú triedu. Zhrňme si preto výhody používania Java Records.
Vo všeobecnosti vieme využívať záznamy v akejkoľvek situácii, kde potrebujeme deklarovať jednoduchý dátový kontajner s vlastnosťami nemeniteľnosti záznamov a chceme využiť automaticky generované metódy. Spomenieme niekoľko scenárov použitia, kedy Java záznamy prídu vhod:
Záznamy môžeme použiť na deklarovanie jednoduchých objektov prenosu údajov, ktoré obsahujú údaje. Je to užitočné pri prenose údajov medzi rôznymi vrstvami aplikácie, napríklad medzi servisnou vrstvou a databázovou vrstvou.
Záznamy možno použiť na deklarovanie konfiguračných objektov, ktoré obsahujú sadu konfiguračných vlastností pre aplikáciu alebo modul. Tieto objekty majú zvyčajne nemenné vlastnosti, vďaka čomu sú bezpečné pre vlákna.
Pri vytváraní REST API je bežné vracať dáta vo forme JSON alebo XML. V takýchto prípadoch chceme definovať jednoduchú dátovú štruktúru, ktorá predstavuje odpoveď API. Záznamy sú na to ideálne, pretože umožňujú definovať ľahkú a nemennú dátovú štruktúru, ktorú možno jednoducho serializovať do formátu JSON alebo XML.
Pri písaní unit testov je často potrebné vytvoriť testovacie dáta pre konkrétny testovací scenár. V takýchto prípadoch sú záznamy na to ideálne, pretože testovacie dáta väčšinou bývajú statické a s minimálnym množstvom kódu vieme vytvoriť komplexnejšie sady testov.
Napriek svojim výhodám records plnohodnotne nenahrádzajú pôvodne JavaBean triedy. Preto, ak potrebujeme:
Java records nám poskytujú elegantný spôsob, ako modelovať nemenné dátové triedy s minimom kódu. Je ideálna najmä pre triedy, ktoré primárne slúžia na uchovávanie dát, umožňujúc vývojárom písať čistejší a ľahšie udržiavateľný kód. Používaním records, množstvo kódu, ktoré je potrebné napísať delegujeme na kompilátor. Pre scenáre zahŕňajúce mutabilné dáta alebo zložité správanie však máme k dispozícií stále tradičné triedy, ktoré v takých prípadoch zostávajú vhodnejšou voľbou.