A Java 22 újdonságai

Elérkezett népszerű sorozatunk új része, amelyben a Java 22 újdonságait mutatjuk be. Cikksorozatunk előző részét, mely a Java 21-ről szól, itt találod meg. Van rengeteg preview feature is, de a Java 22 rengeteg érdekes funkcióval ajándékozott meg bennünket. Ebben a cikkünkben ezekből szemezgetünk.

Amennyiben az összes verzió újdonsága érdekel egy cikkben, ezt a cikket ajánljuk.

super() konstruktor előtti hívások (preview)

Ha nem tudod, mik azok a konstruktorok vagy felfrissítenéd a tudásod ebben a témakörben, ajánlom, hogy nézd meg YouTube-videósorozatunknak ezt a részét:

Ha fejlesztesz Java-ban (és az utóbbi időben nem használtál túl sok Lombok-ot 🙂 ), akkor ismerős lehet, hogy minden egyes konstruktor (az Object-ét kivéve) első utasítása az vagy egy this(…) vagy egy super(…) konstruktorhívás. A this(…) az adott osztályunk valamelyik konstruktorát, a super(…) pedig az ősosztály valamely konstruktorát hívja meg.

Tanulnál többet erről?

Azért vagyunk, hogy segítsünk.

Lehet, hogy ez implicite van ott, ergo nincs leírva, de ettől még ez kerül végrehajtásra. Példának okáért hozzunk létre egy új osztályt:

public class Animal { // implicite itt van, hogy extends Object
    
    public String name;
    
    public Animal(String name) {
        //implicite itt van egy super(); hívás
        this.name = name;    
    }
}

Itt a következő dolgokat figyelhetjük meg:

  • Az általunk létrehozott osztálynak az Object lesz a közvetlen őse, amennyiben nem adunk meg semmit
  • A konstruktorunkon belüli első utasítás egy hívás az ősosztály egyik konstruktorára, amely jelen esetben az Object egyik paraméterek nélküli konstruktora

Fontos megállapítani azt is, hogy amennyiben explicite hívjuk a konstruktort (amely hívásból egyébként 1 és pontosan 1 db lehet konstruktoronként), akkor ez kell az első utasítás legyen, bármilyen ezt megelőző utasítás ugyanis fordítási idejű hibát eredményez. Például a következő osztály esetén két helyen is fordítási idejű hibát kapunk:

public class Animal { // implicite itt van, hogy extends Object

    public String name;

    public Animal(String name) {
        System.out.println("A new instance of Animal is being created"); // fordítási idejű hibát dob
        this();
        this.name = name;
    }

    public Animal(){
        System.out.println("The no-args constructor is being called"); // fordítási idejű hibát dob
        super();
    }
}

Ez az, ami megváltozik ebben a feature-ben a Java 22-től kezdődően. A fenti kód tehát ugyanúgy nem fordulna le, mert this() hívás előtt továbbra sem lehet semmilyen utasítás, viszont a super() előtti konstruktorhívás ennek a feature-nek köszönhetően már engedélyezett.

Fontos, hogy ez egy preview feature, ezért alapértelmezetten nincs engedélyezve a használata. Ha nem tudod, hogy engedélyezd az adott verzióra a preview feature-öket, akkor olvasd el ezt a cikkünket, itt részletesen leírjuk ennek a menetét.

Na de miért hozták meg ezt a döntést…?

Mély tudást szeretnél?

Azért vagyunk, hogy segítsünk.

Tehetnénk fel ezt a kérdést, és nagyon is jogos, mert kardinális változtatásnak tűnik. A legjobb, amiből ki tudunk egy ilyen kérdés megválaszolása esetén, az a hivatalos dokumentáció, ahol mindig leírják azt, hogy az adott döntést milyen szempontok alapján hozták meg és fogják meghozni, és mik az esetleges kockázatok.

Ebben a nagyon hosszú cikkben – amit ettől függetlenül mindenképp javaslok elolvasásra – nagyjából azt írják le, hogy rengeteg olyan helyzet van, amikor lefut az ősosztály konstruktorának a hívása, viszont előtte még bizonyos ellenőrzések még végbe kell menjenek – értelemszerűen ezekhez az ellenőrzésekhez sem az inicializálandó példányunk, sem annak a példányszintű változói nem használhatóak fel, hiszen az az objektum még nem jött létre.

Egy ilyen döntés bevezetésénél mindig szoktak kockázatelemzést is csinálni, amit itt is elvégeztek. Ennek az eredményét a cikk végén olvashatjátok el. Itt azt írják, hogy egyáltalán nem tűnik invazív vagy veszélyes műveletnek. Amire nyilvánvalóan várni kell majd, hogy az IDE-k, a style checker-ek és az olyan statikus kódellenőrzők, mint a SonarQube, felnőjenek ehhez a változáshoz, és ne jelezzenek hibát olyan esetekben, amikor az már nem hiba ennek a funkciónak a bevezetését követően.

Unnamed variables

Voltak korábban olyan kódrészletek, amelyek esetén elkerülhetetlen volt, hogy bizonyos változókat névvel lássunk el úgy, amik a névadást követően viszont használaton kívül voltak. Ennek rengeteg tipikus példája van, ebből egy nagyon gyakori eset, amivel a legtöbb fejlesztő találkozhatott már, az exception-ök kezelése:

String s = ...;
try {
    int i = Integer.parseInt(s);
    ... 
} catch (NumberFormatException ex) {
    System.out.println("Bad number: " + s);
}

Ebben az esetben például a catch blokkban kötelező volt névvel ellátni ezt az ex nevű, NumberFormatException típusú és valamilyen névvel ellátott helyi változót, miközben a névnek ennél a kódrészletnél semmi gyakorlati jelentősége nincs – nem használjuk.

A Java 22 üdítő újdonsága az, hogy ebben az esetben dönthetünk úgy, hogy az adott változónak nem adunk nevet, hiszen nem fogunk rá hivatkozni. Ezt az alulvonás, azaz az underscore karakterrel tudjuk megtenni. A Java 22-től tehát a fenti blokkunk így is kinézhet:

String s = ...
try {
    int i = Integer.parseInt(s);
    ...
} catch (NumberFormatException _) {        // Unnamed variable
    System.out.println("Bad number: " + s);
}

Az ex helyére (ez volt eddig a változó neve) tehát alulvonást tettünk, hiszen az adott változóra semmilyen módon nem szeretnénk hivatkozni.

Ez egy roppant hasznos feature, és fontos, hogy fejlesztőként kövessük az aktuális trendeket, változásokat. Kurzusainkon mi is maximális figyelmet szánunk arra, hogy a legfrissebb technológiákból oktassunk.

Foreign Function and Memory API

Ez a Java 19 óta már preview-ban lévő feature a Java 22-ben véglegesen bekerült a nyelvbe. Korábban ha natív kódot akartunk meghívni a Java-ban, akkor ez belül JNI-vel történt meg, viszont ez performanciában és produktivitásban elavultnak számított, illetve különböző biztonsági aggályok is megjelentek. Röviden tehát a JNI több szempontból törékeny volt már, ezért lecserélték a Foreign Function and Memory API-val (röviden FFM API).

Ez az új API biztonságos, széles körű platform support-ot biztosít, performans, több szálon történő memóriaműveletek esetén is megbízhatóan működik, és beépített feature-e, hogy amennyiben nem biztonságos műveletet hajtasz végre (például C-nél ilyen lehet a már malloc-kal lefoglalt heap terület felszabadításának elfelejtése), akkor jelez a fejlesztőnek.

Várunk sorozatunk következő részében!

Szerző: Nagy Csongor