Project Lombok – A Java Fekete Mágusa
![Lombok](https://ak-akademia.hu/wp-content/uploads/2024/11/24_kep_01.jpg)
Tartalomjegyzék
Boilerplate kód
A Java egyik legnagyobb problémája a boilerplate kód, amit időigényes lehet legenerálni, nehezen olvashatóvá teszi a kódunkat, nehéz karbantartani, és elvonja a figyelmet a tényleges üzleti dologról, aminek a reprezentálására az adott programot írjuk. Nézzük például a következő, embereket reprezentáló osztályt:
import java.util.Objects;
public class Person {
private String name;
private int age;
private String address;
private String motherName;
private String fatherName;
private String email;
public Person(String name, int age, String address, String motherName, String fatherName, String email) {
this.name = name;
this.age = age;
this.address = address;
this.motherName = motherName;
this.fatherName = fatherName;
this.email = email;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", motherName='" + motherName + '\'' +
", fatherName='" + fatherName + '\'' +
", email='" + email + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person person)) return false;
return age == person.age && Objects.equals(name, person.name) && Objects.equals(address, person.address) && Objects.equals(motherName, person.motherName) && Objects.equals(fatherName, person.fatherName) && Objects.equals(email, person.email);
}
@Override
public int hashCode() {
return Objects.hash(name, age, address, motherName, fatherName, email);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getMotherName() {
return motherName;
}
public void setMotherName(String motherName) {
this.motherName = motherName;
}
public String getFatherName() {
return fatherName;
}
public void setFatherName(String fatherName) {
this.fatherName = fatherName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Nem érted a fenti kódot?
Azért vagyunk, hogy segítsünk.
Ha a tényleges üzleti tartalmat nézzük, akkor az osztályunk egy embert reprezentál, viszont a getter-ek, a setter-ek, a konstruktorok, a toString, hashcode és equals override-ok miatt közel száz sornyi programkódot írtunk. Természetesen annyira nem vészes a helyzet így sem, hiszen ezeket a sorokat valószínűleg nem mi írjuk, hanem legeneráljuk az IDE-vel. Az IntelliJ-vel például az Alt + Insert billentyűkombináció lenyomásával tudjuk ezeket legenerálni. Ettől függetlenül körülményes, nehezen olvashatóvá teszi a kódot, és code review esetén is rengeteg felesleges sor, amik közt megbújhat lényegi információ, és több olyan programnyelv van, például a Scala, ahol ilyen típusú kényelmetlenségek nincsenek.
Lombok – mikor használjuk?
A Lombok különösen hasznos olyan projekteknél, ahol sok adattípusú osztály van, például entitásosztályok, DTO-k vagy POJO-k. Ezeknél a rengeteg getter, setter és konstruktor gyorsan átláthatatlan kódot eredményezne. A Lombok megkönnyíti ezek kezelését, és segít a Java kódot olvashatóbbá, hatékonyabbá és karbantarthatóbbá tenni.
Lombok – bemutató
A fenti program a Lombok segítségével így lenne átírható:
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@EqualsAndHashcode
@ToString
public class Person {
private String name;
private int age;
private String address;
private String motherName;
private String fatherName;
private String email;
}
Egyszerűbb, ugye? És ez még nem a legegyszerűbb módja annak, hogy a fenti kódot szimplifikáljuk, hiszen ahogy lent látni fogjuk, a @Data annotáció ezek közül sokat helyettesít 🙂 A következő fejezetben megnézzük, a pom.xml-be vagy build.gradle-be bemásolandó dependenciát.
Maven / Gradle dependencia hozzáadása
Mivel a Lombok egy külső könyvtár, ezért a Java-ban alapértelmezetten nem elérhető: a projekt Maven / Gradle dependenciát hozzá kell adni a projektedhez ahhoz, hogy használni tudd az adott könyvtárat. Amennyiben a központilag elérhető Maven repót használod a projektedhez, ezen az oldalon találsz segítséget, hogy milyen verziók elérhetőek jelenleg, és hogy kell hozzáadni a dependenciát a projektedhez. Fontos megjegyezni, hogy sok cég tiltja a publikus Maven repó használatát, és úgynevezett mirror-olt repókat használnak.
Amennyiben te is ilyen helyzetben vagy, akkor a cég belső dokumentációt érdemes figyelembe venni, a projektek is sok segítséget tudnak nyújtani, illetve ha így sem találod meg a belső mirror repó url-jét, akkor kollégáktól tudsz érdeklődni. A következő pontban a Lombok legfontosabb annotációit vesszük górcső alá.
Lombok annotációk
Nézzük tehát a legfontosabb annotációkat a teljesség igénye nélkül. A teljes listát a Project Lombok oldalán találjátok meg.
@NonNull
: automatikusan null check-et hajt végre az annotált változón@Getter / @Setter:
automatikusan legenerálják a getter-eket és setter-eket az annotált field-eknek vagy az annotált osztály field-jeinek. Széleskörűen konfigurálható (pl. az access level tetszőlegesen beállítható bármire, de alapértelmezetten természetesen public).@ToString
,@EqualsAndHashCode
: lenegerálja egy alapértelmezett toString, illetve equals + hashcode metódust az annotált osztálynak.@NoArgsConstructor
: az annotált osztály kap egy argumentumok nélküli konstruktort@AllArgsConstructor:
az annotált osztály kap egy olyan konstruktort, amely minden field-et inicializál@RequiredArgsConstructor
: ez az annotáció a hivatalos leírás szerint a különleges elbírálást igénylő field-ek inicializálására létrehozott konstruktor. Ez a gyakorlatban a final módosítóval, illetve a valamilyen okból kifolyólag nem inicializált field-eket jelenti.@Builder
: egy remek mód arra, hogy használjuk a builder design pattern-t Java-ban, mindenféle boilerplate kód nélkül@Data
: ez az annotáció egyben tartalmazza a leggyakrabban használt funkciókat: egyesíti az@RequiredArgsConstructor
, a@ToString
, a@HashcodeAndEquals
, a@Getter
és a@Setter
field-eket.@Value
: a@Data
immutable variánsa- Logging: a Lombok rengeteg annotációt biztosít a modern logging egyszerűbbé tételére, például ilyenek a
@Log
vagy az@Slf4j
. Bővebb információt ezekről a funkciókról itt olvashatsz.
Szeretnél megtanulni programozni?
Azért vagyunk, hogy segítsünk.
A Java-ba már bevezetett feature-ök
Ebben a fejezetben olyan feature-öket nézünk át, amik eredetileg a Lombok részeiként indultak el, de ma már a hivatalos Java is nyújt rájuk megoldást, ezért ma már ezek kevésbé használtak:
- A Java 10-ben bemutatott var kulcsszó is a Lombok része volt korábban. Ha érdekel, melyik verzióban milyen feature került bemutatásra, ezt az összehasonlító cikkünket ajánlom.
- A @Cleanup annotáció a try-with-resources nélküli világban nagy segítség volt számunkra. A Java 7 óta azonban van Java-n belüli megoldásunk is a problémára.
Rekordok vs Lombok
Érdekel, hogy mikor használd a Lombok @Data és @Value annotációit, és mikor használd a Java 16-ban véglegesített rekordokat? Akkor olvasd el a Java 16 újdonságairól szóló cikkünknek ezt a bekezdését, és itt mindent elmagyarázunk!
A Lombok kritikája
Beszéltünk pár szót az eszköz előnyeiről, most említsük meg a hátrányaiból is néhányat, hiszen, mint tudjuk, semmi sem fenékig tejfel. 🙂 A Lombok számos előnnyel jár, amelyek kétségtelenül vonzóvá teszik a Java fejlesztők számára, ugyanakkor nem árt tisztában lenni a használatával járó hátrányokkal és kihívásokkal. Bár Lombok megkönnyítheti a fejlesztést, a következő szempontokat érdemes figyelembe venni a döntés előtt.
IDE-támogatás és pluginoktól való függőség
A Lombok megfelelő működéséhez speciális IDE-támogatás szükséges, különösen, mivel sok IDE alapértelmezés szerint nem képes értelmezni a Lombok annotációkkal létrehozott metódusokat. Például az Eclipse és az IntelliJ IDEA esetében pluginokat kell telepíteni, hogy az IDE „lássa” és felismerje a Lombok által generált metódusokat, illetve pl. IntelliJ IDEA-ben be kell kapcsolni az úgynevezett annotation processing funckiót, hogy megfelelően működjön.
Ha a projektet olyan fejlesztők használják, akik nem telepítették ezeket a pluginokat, az IDE-ben láthatatlan vagy „hibás” kódok jelenhetnek meg, ami a csapat számára zavaró lehet. A karbantartás és frissítések miatt is folyamatos figyelmet igényel, hogy minden fejlesztő környezete kompatibilis legyen a Lombok verziójával.
Rejtett kód és átláthatóság csökkenése
Bár a Lombok eltünteti a boilerplate kódot, ezzel egyúttal láthatatlanná is teszi azokat a metódusokat, amelyeket a kód karbantartói esetleg manuálisan áttekintenének. Ha például valaki a @Getter
és @Setter
annotációkat használja egy osztályon, akkor a generált getter és setter metódusok nem jelennek meg explicit módon a forráskódban. Ez különösen problémás lehet, ha a generált metódusok viselkedését módosítani vagy figyelni szeretnénk.
Emiatt a Lombok-annotációkat használó kód kevésbé „önálló” és nehezebb a megértése azok számára, akik esetleg nem ismerik a Lombok működését. Egy új fejlesztő számára kihívás lehet kitalálni, hogy az annotációk hogyan és mit generálnak, mivel a tényleges forráskódban ezek a metódusok nem jelennek meg.
Hibakeresési nehézségek és a generált kód megértése
Mivel a Lombok generálja a metódusokat és bizonyos kódokat, a hibakeresés és a debugolás során a hibaforrás megtalálása nehezebbé válhat. A Lombok által generált kód gyakran nem jelenik meg közvetlenül az IDE-ben, ami azt eredményezi, hogy a fordító vagy futásidő során keletkezett hibák nem azonnal világosak.
Egy egyszerű getter/setter probléma hibakeresése is összetett lehet, mivel a hibák visszavezetése az annotációra nem olyan egyértelmű, mint egy explicit módon megírt metódus esetében. Ez különösen kritikus lehet összetett hibák esetén, amelyek rejtett módon jelennek meg a generált kódban, de amelyekhez nincs egyértelmű kapcsolódási pont a forráskódban.
Kompatibilitási és verziókezelési problémák
A Lombok egy külső könyvtár, amely folyamatos karbantartást és frissítéseket igényel, különösen, ha újabb Java verziók vagy egyéb könyvtárak kerülnek bevezetésre a projektben. Az új Java verziók támogatása időnként késhet Lombok esetében, ami miatt egyes annotációk vagy funkciók inkompatibilisek lehetnek a Java legfrissebb verzióival.
Ezenkívül, ha más könyvtárak vagy eszközök is vannak a projektben, amelyek hasonló funkcionalitást nyújtanak (pl. Jackson az objektumok JSON-ként való kezeléséhez), akkor előfordulhatnak ütközések a generált metódusok között, különösen, ha az osztályokon ugyanazon mezőkön használnak különböző annotációkat.
Csökkentett kódkontroll és konfiguráció hiánya
A Lombok egy „mindent vagy semmit” megközelítést alkalmaz, ami azt jelenti, hogy az annotációk által generált metódusokat nem lehet könnyen testre szabni. Például, ha a @Getter
annotációt használjuk egy mezőre, akkor Lombok egy szokásos getter metódust generál, de nincs lehetőség arra, hogy módosítsuk a viselkedését anélkül, hogy explicit kódot írnánk. Ez korlátozhatja a fejlesztőket abban, hogy teljes kontrollt gyakoroljanak a generált kód felett.
Külső eszköztől való függés
A Lombok hozzáadása a projekthez egy további függőséget jelent, amelytől a projekt működése részben függ. Ha a Lombok fejlesztése leáll, vagy ha inkompatibilis frissítéseket vezetnek be, ez közvetlen hatással lehet a projektünkre. A kódunk hosszú távú fenntarthatóságát is kockáztathatjuk, mivel ha valamikor el kell távolítani a Lombok-ot a projektből, akkor nagy mennyiségű kódot kellene újraírni.
Itt megjegyzem, hogy sok belsős, céges projektben tiltják a külső tool-ok használatát, ezért vannak helyek, ahol a Lombok egyáltalán nem opció.
A fejlesztő tanulási folyamatának lassítása
A Lombok rendkívül kényelmes eszköz, amely megkímél a boilerplate kód írásától, viszont ha valaki túlzottan hozzászokik az általa nyújtott megoldásokhoz, az hosszú távon akadályozhatja a Java alapjainak mélyebb megértését. Lombok elrejti a getterek, setterek, konstruktorok és egyéb metódusok generálásának pontos részleteit, és bár ez időt takarít meg, azt is jelentheti, hogy a fejlesztő kevesebb tapasztalatot szerez a Java alapvető mechanizmusairól.
Ez különösen fontos lehet, ha valaki tanulási fázisban van, vagy hosszú távon szeretne fejlődni a Java-ökoszisztémában. A kód megírása ugyanis egy lehetőség a Java alapvető elvei és szintaxisa mélyebb elsajátításához, és ennek kihagyása visszaüthet, ha bonyolultabb helyzetekben kell megérteni, javítani vagy optimalizálni a programkódot.
Pont ezért javasoljuk, hogy amennyiben kezdő vagy és a Java videókurzusunkat nézed, akkor még ne használd ezt a rendkívül potens eszközt egészen addig, amíg az objektumorientáltság alapjait megfelelően el nem sajátítod. Ezt a témát ettől a résztől kezdődően kezdjük el feldolgozni:
Végszó
A Lombok egy rendkívül hasznos eszköz, amely számos pontok megkönnyíti a fejlesztői munkát és csökkenti a boilerplate kódokat a rendszerünkben, ezzel bizonyos szempontból növeli az átláthatóságot, csökkenti a code review-k komplexitását és rengeteg egyéb kényelmi előnnyel jár. Természetesen, mint mindennek, hátrányai és limitációi is vannak, és ezeknek az ismeretében dönthető el, hogy egy adott projekthez használjunk-e egy adott keretrendszert vagy ne.
Ha érdekel a programozás, akkor nézz körül blogcikkeink és tanfolyamaink közt!
Szerző: Nagy Csongor