A Java fejlesztési környezet legújabb verziója, a Java Development Kit (JDK) 24, 2025. március 18-án érkezik, és rengeteg újítást ígér. Az előző verzióhoz, a JDK 23-hoz képest, amely 12 hivatalos funkcióval debütált, a JDK 24 impozáns 21 javasolt újítással büszkélkedhet. Az új verzió főként a kvantumszámítógépes támadásokkal szembeni védekezést, a fejlesztői hatékonyság növelését és a modern számítástechnikai környezetekhez való alkalmazkodást helyezi előtérbe. Ebben a bejegyzésben áttekintjük a legfontosabb új funkciókat és azok jelentőségét.
Kvantumszámítógépes támadásokkal szembeni védekezés
A JDK 24 egyik legizgalmasabb újítása a kvantumrezisztens modul-rácsalapú kulcsbecsomagolási mechanizmus (ML-KEM) és a digitális aláírási algoritmus (ML-DSA) bevezetése. Ezek a technológiák a jövőbeni kvantumszámítógépes támadások kivédését célozzák.
ML-DSA: Biztosítja az adatok integritását és az aláíró hitelességét, megvédve a digitális aláírásokat az illetéktelen módosításoktól.
ML-KEM: Képes nyilvános kulcsú titkosítással biztonságosan továbbítani szimmetrikus kulcsokat nem biztonságos kommunikációs csatornákon keresztül.
Ez az újítás kulcsfontosságú az olyan alkalmazások számára, amelyek hosszú távú adatbiztonságot igényelnek, különösen a digitális aláírásokat és adatcseréket illetően.
A fejlesztői hatékonyság növelése
Rugalmas konstruktorok
A rugalmas konstruktoroknak ez immár a harmadik előzetese hiszen a JDK 22-ben és 23-ban is szerepelt, igaz akkor még más néven futott. Eredetileg csak úgy hívták, hogy „utasítás a super() előtt”, ami egy eléggé jó leíró jellegű elnevezés, hiszen pontosan erről van szó. A Javaban az egy meglehetősen régi és közismert szabály, hogy ha egy leszármazott osztály konstruktorában meg akarjuk hívni az ősosztály konstruktorát akkor az a super() utasítással tehetjük meg, amelynek szigorúan az első utasításnak kell lennie a konstruktoron belül. Ez utóbbi szabállyal azaz, hogy mindenképpen az első utasításnak kell lennie számol le a rugalmas konstruktor koncepció bizonyos körülmények között. A super()hívása előtti kódokat egy külön kontextusban egy úgynevezett prekonstrukciós kontextusban kezelik, ezáltal csak bizonyos utasítások szerepelhetnek itt, úy mint például a konstruktor argumentumokra vonatkozó számítások validálások:
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0) {
throw new IllegalArgumentException("non-positive value");
}
super(Long.toString(value));
}
}
Előzetes osztálybetöltés és kapcsolás
Az új előzetes osztálybetöltési mechanizmus (AOT) javítja az alkalmazások indítási sebességét azáltal, hogy az alkalmazás osztályai azonnal elérhetővé válnak betöltött és összekapcsolt állapotban, amikor a HotSpot Java virtuális gép elindul. Ez úgy érhető el, hogy az alkalmazást egy futtatás során megfigyelik, és az összes osztály betöltött és összekapcsolt formáját egy gyorsítótárban tárolják a későbbi futtatások során történő felhasználás céljából.
Scoped értékek: Egyszerűbb és hatékonyabb adatmegosztás
A scoped értékek lehetővé teszik, hogy egy metódus megváltoztathatatlan adatokat osszon meg a szálon belüli hívott metódusokkal és gyermekszálakkal. Ezek az értékek könnyebben kezelhetők, mint a helyi szálváltozók, és különösen hatékonyak, ha virtuális szálakkal és strukturált párhuzamossággal együtt használják őket.
Az API elsőként a JDK 20-ban jelent meg inkubációs szakaszban, majd előzetesként a JDK 21-ben, továbbfejlesztve a JDK 22 és JDK 23 során. A JDK 24 egy újabb előzetes verziót mutat be, amely tovább finomítja ezt a funkciót.
A Java ökoszisztéma modernizálása
A biztonsági menedzser végleges letiltása
A biztonsági menedzser, amelyet már a Java 17-ben elavultnak nyilvánítottak, végleg eltávolításra kerül. Ennek célja a platform egyszerűsítése, mivel a menedzsert évek óta nem használják széles körben sem kliens-, sem szerveroldali biztonsági megoldásokra.
Modul import deklarációk
A moduláris könyvtárak egyszerűbb újrafelhasználását segítik a modul import deklarációk, amelyek egyetlen utasítással lehetővé teszik a modul összes exportált csomagjának importálását, de nem követeli meg, hogy az importáló kód maga is modul legyen. A JDK 23-ban ez a funkció mint előzetes egyébként már szerepelt.
Kulcsszármaztató függvény (KDF) API
A JDK 24 egy új kulcsszármaztató függvényekhez (Key Derivation Functions, KDF) kapcsolódó API-t vezet be, amely lehetővé teszi további kulcsok előállítását egy titkos kulcsból és más adatokból. Az API célja, hogy a biztonsági szolgáltatók megvalósíthassák a KDF algoritmusokat Java kódban vagy natív kódban, attól függően, hogy melyik a megfelelőbb.
Az API olyan népszerű KDF algoritmusokat támogat majd, mint például a HMAC-alapú kivonási és kiterjesztési kulcsszármaztatási függvény (RFC 5869) és az Argon2 (RFC 9106). Ezáltal a fejlesztők egyszerűen integrálhatják ezeket az erős kriptográfiai megoldásokat alkalmazásaikba.
A JNI használatának korlátozására való felkészülés
A JNI használatának korlátozására való felkészülés nevű JDK 24-es funkció célja, hogy figyelmeztetéseket adjon a JNI használatára vonatkozóan, és a JDK 22-ben bemutatott foreign function and memory (FFM) API-t úgy módosítja, hogy egységes figyelmeztetéseket küldjön. Ezek a figyelmeztetések előkészítik a jövőbeli kiadásokra, amelyek alapértelmezés szerint biztosítják az integritást, és egységesen korlátozzák a JNI és az FFM API használatát. A célok között szerepel a JNI megőrzése, mint a natív kóddal való interoperabilitás szabványos módja, a Java ökoszisztéma felkészítése a jövőbeli kiadásokra, amelyek alapértelmezés szerint megtiltják a natív kóddal való interoperabilitást, valamint a JNI és az FFM API használatának összehangolása, hogy a könyvtárkarbantartók könnyen migrálhassanak az egyik API-ról a másikra anélkül, hogy a fejlesztőknek parancssori opciókat kellene módosítaniuk.
Teljesítményoptimalizálás
Generációs Shenandoah szemétgyűjtő
A generációs Shenandoah kísérleti generációs gyűjtési képességekkel bővítené a szemétgyűjtőt, hogy javítsa a fenntartható teljesítményt, a terhelés-kiugrással szembeni ellenállást és a memóriahasználatot. A fő cél a kísérleti generációs üzemmód biztosítása, a nem generációs Shenandoah megszakítása nélkül. A generációs üzemmód a tervek szerint egy jövőbeli kiadásban alapértelmezett üzemmóddá válik.
Tömörített objektumfejlécek
Az objektumfejlécek mérete jelentősen csökken (96-128 bitről 64 bitre) 64 bites architektúrákon, ami kisebb heap memóriaterületet igényel és jobb adatlokalitást biztosít, különösen a felhőalapú környezetekben.
Futtatási képek összekapcsolása JMOD-ok nélkül
A JDK méretének körülbelül 25%-os csökkentését célozza az új funkció, amely lehetővé teszi a jlink eszköz számára egyedi futtatási képek létrehozását JMOD fájlok nélkül. Ez az újítás különösen hasznos a felhőalapú környezetekben, ahol a tartalmazott JDK-val ellátott konténerképeket gyakran másolják a hálózaton. A kisebb méretű JDK hatékonyabbá teszi az ilyen műveleteket, csökkentve a hálózati erőforrásigényt és gyorsítva a konténerek kezelését.
Virtuális szálak szinkronizálása rögzítés nélkül
Ez a fejlesztés a Java kód méretezhetőségének javítását célozza, amely szinkronizált metódusokat és utasításokat használ. A megoldás lehetővé teszi, hogy a blokkoló virtuális szálak felszabadítsák az általuk használt platformszálakat, így más szálak rendelkezésére bocsátják azokat. Ez a változtatás gyakorlatilag megszünteti a virtuális szálak platformszálakhoz való rögzítését, ami korlátozta a párhuzamosan kezelhető virtuális szálak számát. Az eredmény egy nagyobb teljesítőképességű és hatékonyabb alkalmazás-végrehajtási környezet.
A nem-generációs ZGC mód eltávolítása
A JDK 24 keretében tervezik a nem-generációs Z Garbage Collector (ZGC) mód eltávolítását, amely a karbantartási költségek csökkentését célozza. Jelenleg két ZGC mód fenntartása hátráltatja az új funkciók fejlesztését. A javaslat szerint a generációs ZGC a legtöbb felhasználási esetben jobb megoldást kínál, mint a nem-generációs változat.
A terv részeként a ZGenerational opciót elavulttá nyilvánítják, és a nem-generációs ZGC kódját, valamint a hozzá kapcsolódó teszteket eltávolítják. A nem-generációs mód egy jövőbeli kiadásban teljesen megszűnik, és a HotSpot JVM nem fogja felismerni, így nem indul el vele.
Vector API
A Vector API célja, hogy lehetővé tegye vektoralapú számítások kifejezését, amelyek futási időben megbízhatóan optimalizált vektorinstrukciókká fordulnak a támogatott CPU architektúrákon, így jobb teljesítményt biztosítanak a hasonló skaláris számításokhoz képest. A JDK 16 és JDK 23 között már inkubálásra került, és a JDK 24-ben újra inkubálják, de az API-ban nem lesznek jelentős változások a JDK 23-hoz képest.
A cél az, hogy a vektoralapú számításokat platformfüggetlenül és világosan fejezze ki az API, biztosítva megbízható futásidejű fordítást és teljesítményt az x64 és AArch54 architektúrákon. Az API azokat a vektoralapú műveleteket is támogatja, amelyek nem fejezhetők ki a futási időben, és azok szépen fokozatosan lelassulnak, de még mindig működnek. Emellett az API illeszkedik a Project Valhalla-hoz, amely a Java objektummodellt fejleszti tovább.
A G1 szemétgyűjtőt érintő módosítás
A G1 garbage collector késői gátló bővítése a G1 gátlók megvalósítását egyszerűsíti. Az új megközelítés a memória-hozzáférési információkat a C2 fordítási folyamat későbbi szakaszaiba helyezi, csökkentve ezzel a fordítási időt a G1 használatakor. A cél az, hogy a G1 gátlók érthetőbbé váljanak a HotSpot fejlesztők számára, és biztosítva legyen, hogy a C2 megőrzi a memória-hozzáférések, biztonsági pontok és gátlók közötti helyes sorrendet. Továbbá a fejlesztés célja a C2 által generált JIT kód minőségének megőrzése mind sebességben, mind méretben.
Nyelvi fejlesztések
Primitív típusok használata mintázatokban és switch kifejezésekben
A primitív típusok mostantól minden mintázatban és környezetben használhatók, beleértve az instanceof és switch utasításokat is. Ennek a funkciónak immár a második előzetese válik elérhetővé a JDK 24-ben.
Célok:
Egységes adatfeltárás lehetővé tétele a típusminták engedélyezésével minden típusra, legyen az primitív vagy referencia típus.
A típusminták összehangolása az instanceof, és az instanceof összehangolása a biztonságos típuskonverzóval.
A mintaillesztés lehetővé tétele primitív típusok használatára mind a beágyazott, mind a legfelső szintű mintaösszefüggésekben.
Könnyen használható konstrukciók biztosítása, amelyek kiküszöbölik a nem biztonságos típuskonverziók miatti információvesztés kockázatát.
A switch Java 5 (enum switch) és Java 7 (string switch) továbbfejlesztését követően lehetővé teszi, hogy a switch bármilyen primitív típusú értéket feldolgozzon.
Példa instanceof használatára:
if (i instanceof byte b) {
... b ...
}
Példa switch használatára:
long v = ...;
switch (v) {
case 1L -> ...;
case 2L -> ...;
case 10_000_000_000L -> ...;
case 20_000_000_000L -> ...;
case long x -> ... x ...;
}
Egyszerű forrásfájlok és példányosított fő metódusok
A kezdő Java programozók életét könnyíti meg az egyszerűsített nyelvi szintaxis, amely kevesebb bonyolult struktúrát igényel, miközben lehetővé teszi a fejlettebb funkciók használatát. Egy példával megvilágítva, ez a következőképpen nézne ki. Abban az esetben ha mondjuk egy rövid egyosztályos kódot kellene írnunk ami a konzolról olvas be adatokat akkor rögtön a következő kódstruktúrára van szükség:
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = reader.readLine();
...
} catch (IOException ioe) {
...
}
Ez a kezdők számára enyhén riasztó, de tapasztalt fejlesztők is inkább más programozási nyelvekhez nyúlnának, ha tényleg csak egy rövidke kis script összeütése a cél. Ezzel szemben ez az immár negyedik előzetes fázisban lévő javaslat valami ilyesmi szerkezet javasolna:
void main() {
String name = readln("Please enter your name: ");
print("Pleased to meet you, ");
println(name);
}
Ez mindenképpen egy lényegesen kevésbé szószátyár megoldás lenne.
Stream gatherers (Stream összegyűjtők)
A JDK 24-ben a stream API egy új funkcióval bővül, amely lehetővé teszi a testreszabott köztes műveletek alkalmazását. A stream gatherers lehetővé teszik, hogy a stream-pipeleineken adatokat olyan módon alakítsunk át, amelyek a meglévő beépített köztes műveletekkel nem valósíthatók meg könnyen.
A célja, hogy a stream-pipeline-ek rugalmasabbak és kifejezőbbek legyenek, emellett lehetőséget biztosít arra is, hogy a felhasználók egyedi köztes műveleteket alkalmazzanak, amelyek még végtelen méretű streamekkel is működnek. A funkció előzetes verzióját már a JDK 22-ben és JDK 23-ban bemutatták, és a JDK 24-ben véglegesítik.
Class-file API
A Class-file API, amelyet már a JDK 22-ben és JDK 23-ban előzetesen bemutattak, a JDK 24-ben véglegessé válik, néhány kisebb módosítással. Ez az API szabványos eszközként szolgál a Java osztályfájlok elemzésére, generálására és átalakítására. Célja, hogy olyan API-t biztosítson, amely követi az osztályfájl formátumot, amit a Java Virtual Machine (JVM) specifikációja határoz meg.
Ezen kívül a második célja, hogy lehetővé tegye a JDK komponensek számára, hogy áttérjenek erre a szabványos API-ra, és végül eltávolítsák a JDK belső másolatát a harmadik féltől származó ASM könyvtárról. A második előzetes verzió óta történt változások között szerepelnek az enum értékek átnevezése, bizonyos mezők eltávolítása, új metódusok és metódus túlterhelések hozzáadása, metódusok átnevezése, valamint olyan interfészek és metódusok eltávolítása, amelyek már nem szükségesek.
Hosszú távú kilátások
A JDK 24 nem hosszú távú támogatással rendelkező (LTS) kiadás, ezért várhatóan kevesebb vállalati alkalmazásban fogkák használni majd, mint az LTS verziók, például a JDK 21-et vagy a várhatóan 2025-ben megjelenő JDK 25-öt. Ennek ellenére a JDK 24 jelentős előrelépést képvisel a Java ökoszisztéma fejlesztésében, különösen a kvantumrezisztens technológiák és a fejlesztői hatékonyság terén.