A Java 23 újdonságai

Java 23

Sorozatunk előző cikkében a Java 22 újdonságaival foglalkoztunk. Ma a Java 23 által bevezetett 12 innovációból szemezgetünk.

A Java 23-ban megjelenő feature-ök többsége preview, és többel közülük már sok verzióval ezelőtt elkezdtek kísérletezgetni. Ilyen szempontból a rekorder egyértelműen Vector API, ami már a nyolcadik inkubátor kiadását éli meg. A Vector API első inkubátor kiadása még a Java 16-ban jelent meg, úgyhogy jó ideje húzzák már ezt a funkciót 🙂 Kíváncsian várjuk, mikor kerül be a végleges kiadásba.

Amennyiben nincs időd elolvasni minden verzió újdonságait külön-külön (tudom, van pár :)), ezt az összesítő cikkünket javaslom. Nézzük tehát a Java 23 legfontosabb újdonságait!

ZGC: alapértelmezett Generational Mode

Bár erről szóló cikkünkben nem írtunk róla részletesen, de a Java 21-ben a kijött az ún. Generational ZGC azzal a szándékkal, hogy az előző, ún. non-generational ZGC-t elavulttá nyilvánítsák és szépen-lassan kivezessék a Java-ból.

Mi az a ZGC?

Viszont mi az a ZGC? A ZGC egy olyan GC algoritmus, amely a Java 11-ben jelent meg először kísérleti feature-ként, és a Java 15-ben véglegesítették, és többszálú, sokkal nagyobb heap kezelésére képes, mint a korábbi GC algoritmus, mindezt minimális pause time-okkal.

Mi az a GC?

A GC a garbage collector rövidítése, és nagyon egyszerűen egy olyan algoritmusról beszélünk, ami a JVM-en belüli heap-et pásztázza a memóriát (pontosabban a heap-et) és megszünteti azokat az objektumokat, amelyekre már nem mutat referencia.

Profiktól tanulnál?

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

Ahhoz, hogy megértsük, mi történik pontosan, menjünk vissza a C nyelvre egy pillanat erejéig. Ha a C-ben létrehozok valamit a heap-en (malloc függvény), akkor a lefoglalt memóriaterület felszabadításáról nekem kell gondoskodnom: meghívom a free függvényt, amikor már nincs szükségem az adott adatra.

Ezzel szemben a Java-ban az objektumok megszüntetéséről egy automatizmus gondoskodik, és ezzel levesz egy nagyon fontos felelősséget a fejlesztő válláról.

Mi az a pause time?

Két bekezdéssel feljebb említettem, hogy a ZGC esetében minimális a pause time – na de mi az? A pause time a szemétgyűjtő algoritmusok működése során azt az időt jelenti, amikor a program futása megáll vagy lelassul, hogy a garbage collector elvégezhesse a memóriakezelési feladatokat. Ilyenkor a szemétgyűjtő megkeresi és felszabadítja a már nem használt objektumokat, így több szabad memória áll rendelkezésre. Minél hosszabb a „pause time”, annál inkább észrevehető a program lassulása a felhasználók számára, ezért sok GC algoritmus célja ennek az időnek a minimalizálása a gördülékenyebb működés érdekében.

A ZGC-nél egyébként a maximális garantált pause time a milliszekundum törtrésze, így ez azokban az helyzetekben, ahol a Java-t alkalmazzák, nem jelent problémát.

Mit jelent az, hogy generational?

A Generational ZGC lényege az, hogy külön generációkat tart létre az újonnan és régen létrejött object-eknek, így a ,,fiatal” object-eket – amik a megfigyelés alapján korán szűnnek meg -, gyakrabban össze lehet gyűjteni. Ezt úgy lehet megvalósítani, hogy ha a fiatal, relatíve frissen létrejött objektumokat egy másik memóriatérben tároljuk, mint az idősebbeket. A szakirodalom egyébként ezeket a ciklusokat nevezi minor, illetve major cycle-nek.

A garbage collection kifejezetten egy olyan téma, amire szeretnek rákérdezni az interjúztatók és fontos ahhoz, hogy megértsük, mi történik a háttérben, amikor írunk egy programot, éppen ezért a tanfolyamainkon is kiemelt szerepet biztosítunk annak, hogy hallgatóink megértsék a GC alapvető szerepét és működését.

Markdown kommentek

Korábban ha a kódba akartunk kommentet írni (ezt hívjuk JavaDoc-nak), ezt kizárólag egy sajátos HTML nyelven tudtuk megcsinálni, amit ehhez hasonló Java-specifikus elemek díszítettek: {@code hashCode}. A tapasztalt szemnek teljesen érthető, hogy ez mi, de meg lehetne ezt egyszerűbben is oldani.

Éppen ezért üdítő újdonság, hogy a java 23-tól Markdown-ban is meg lehet írni ezeket a kommenteket, ami egy hangyányival egyszerűbbé, letisztultabbé és átláthatóbbá. teszi a dokumentációnkat Markdown-t egészen biztosan láttál már, akár a Hackerrank feladatai között böngészve, akár egy GitHub lévő projekten .md fájljára gondolsz.

Magáról a funkcióról itt olvashatsz többet, és itt is megragadnám az alkalmat arra, hogy ajánljam a hivatalos dokumentációt olvasgatásra, tanulásra.

Modul import deklarációk (preview)

Ennek a funkciónak a célja röviden az, hogy egy adott modul által exportált package-eket egy utasítás keretében be lehessen importálni. Ez jelentős egyszerűsítés ahhoz képest, hogy minden osztályt külön be kellett importálni úgy, hogy a package hierarchiáját ismerned kellett. A hivatalos dokumentáció, amit természetesen minden esetben javaslok elolvasásra, adott egy példát, ahol a beimportált könyvtárak jelentősen hosszabbá teszik a kódunkat:

import java.util.Map;                   // or import java.util.*;
import java.util.function.Function;     // or import java.util.function.*;
import java.util.stream.Collectors;     // or import java.util.stream.*;
import java.util.stream.Stream;         // (can be removed)

String[] fruits = new String[] { "apple", "berry", "citrus" };
Map<String, String> m =
    Stream.of(fruits)
          .collect(Collectors.toMap(s -> s.toUpperCase().substring(0,1),
                                    Function.identity()));

És valóban, egy viszonylag egyszerű, pár soros kód esetén is 4 db importunk van, ami majdnem olyan hosszú, mint maga a megírt kódunk. A megoldás az import module statement lesz, ami a következőképpen fog kinézni ebben a konkrét esetben:

import module java.base;

String[] fruits = new String[] { "apple", "berry", "citrus" };
Map<String, String> m =
    Stream.of(fruits)
          .collect(Collectors.toMap(s -> s.toUpperCase().substring(0,1),
                                    Function.identity()));

Tömörebb, egyszerűbb, viszont egy dologra figyelned kell: ha egy több modult importálsz, megtörténhet, hogy a ugyanaz az osztálynév több helyen is szerepel – például a java.base és a java.desktop modulok importálása esetén a következő sor fordítási idejű hibával fog elszállni:

import module java.base;      // exports java.util, which has a public List interface
import module java.desktop;   // exports java.awt, which a public List class

...
List customList = ...         // Error - Ambiguous name!
...

Ennek az oka, ahogy a kommentekben is olvashatod, hogy a fordító nem fogja tudni, hogy java.util.List-et vagy a java.awt.List-et importálja-e be 🙂

Friss tudást szeretnél?

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

Ki szeretnéd próbálni az import module-t? Hajrá, viszont emlékezz rá, hogy ez egy preview feature, így alapértelmezetten nem elérhető a Java 23-ban, külön engedélyezni kell. Arról, hogy ezt hogy tudod megtenni, itt olvashatsz részletesen.

Amennyiben új vagy a Java-ban, és érdekel a nyelv, javasoljuk, hogy kezdd el nézni ingyenesen elérhető YouTube videósorozatunkat! A sorozat első részét lent is megtekintheted:

Köszönöm, hogy velünk tartottál, várunk sorozatunk következő részénél!

Szerző: Nagy Csongor