actu-image
Software engineering PL - 16 wrz 2026

Java 27: nowości, których nie można przegapić

Artykuł napisany przez
Achraf HASBI
Practice Leader, coach i Java Expert w MARGO

Java 27, wydana 15 września 2026 r., kontynuuje 6-miesięczny cykl wydawniczy Javy jako drugie wydanie non-LTS po Javie 25. Podczas gdy Java 25 pozostaje aktualnym wydaniem z długoterminowym wsparciem (Long-Term Support – LTS), Java 27 przynosi znaczące usprawnienia w zakresie wydajności pamięci, garbage collection, bezpieczeństwa, obserwowalności oraz ekspresyjności języka.

To wydanie zawiera 9 JEP-ów: 4 sfinalizowane, 4 w trybie preview i 1 w fazie inkubacji. W tym artykule przyjrzymy się nowym funkcjom Javy 27, ze szczególnym uwzględnieniem sfinalizowanych JEP-ów oraz ich wpływu na tworzenie oprogramowania w Javie.

Uwaga : Pobierz OpenJDK 27 tutaj: https://jdk.java.net/27/


JVM

JEP 523 : G1 jako domyślny Garbage Collector we wszystkich środowiskach

G1 jest domyślnym garbage collectorem w Javie od wersji Java 9, ale nie wszędzie. Do wersji Java 26 JVM HotSpot automatycznie przełączał się na Serial GC podczas pracy w środowiskach z ograniczeniami, posiadających tylko jeden procesor (CPU) lub mniej niż 1792 MB pamięci fizycznej.

Takie zachowanie miało sens, gdy G1 wprowadzano jako rozwiązanie domyślne. Serial GC ma bardzo prostą implementację i historycznie zapewniał wyższą przepustowość (throughput) oraz mniejszy ślad pamięciowy (memory footprint) na maszynach o ograniczonych zasobach.

Jednak G1 znacząco ewoluował od czasów Javy 9. Jego natywny ślad pamięciowy został zmniejszony, a niedawne usprawnienia stopniowo zredukowały różnicę w przepustowości względem Serial GC. W Javie 26 JEP 522 usunął narzut synchronizacyjny z barier zapisu (write barriers) w G1 poprzez wprowadzenie drugiej tablicy kart (card table), co przyniosło znaczący wzrost przepustowości.

Wraz z JEP 523 Java 27 wieńczy tę ewolucję: G1 jest teraz domyślnym garbage collectorem w każdym środowisku, niezależnie od liczby dostępnych procesorów czy wielkości pamięci fizycznej.

Serial GC nie zostaje usunięty. Aplikacje, które korzystają z jego właściwości, nadal mogą go jawnie wybrać:

java -XX:+UseSerialGC -jar application.jar

Podobnie aplikacje, które już jawnie wybierają G1, ZGC, Parallel GC, Shenandoah lub inny dostępny collector, pozostają nienaruszone.

JEP 534 : Domyślnie skompaktowane nagłówki obiektów (Compact Object Headers)

JEP 534 sprawia, że skompaktowane nagłówki obiektów (Compact Object Headers) stają się domyślnym układem nagłówków obiektów w 64-bitowej JVM HotSpot.

Compact Object Headers są częścią Projektu Lilliput, którego celem jest redukcja śladu pamięciowego obiektów Java poprzez zmniejszenie ich nagłówków z 96 bitów do 64 bitów na architekturach 64-bitowych.

Napisałem już dedykowany, szczegółowy artykuł na temat Projektu Lilliput, układu pamięci obiektów w Javie oraz JEP 519, w którym wyjaśniam szczegółowo, jak obiekty Java są reprezentowane w pamięci, jak działają ich nagłówki i jak Compact Object Headers mogą znacząco zredukować zużycie pamięci.

Przed Javą 27 nagłówki Compact Object Headers musiały być włączane jawnie:

java -XX:+UseCompactObjectHeaders -jar application.jar

Od Javy 27 nic nie jest wymagane:

java -jar application.jar

JVM automatycznie używa skompaktowanego układu. Aplikacje, które muszą powrócić do tradycyjnego układu nagłówków obiektów, nadal mogą jawnie wyłączyć tę funkcja:

java -XX:-UseCompactObjectHeaders -jar application.jar

JEP 536 : Redagowanie danych w procesie przez JFR (In-Process Data Redaction)

JDK Flight Recorder (JFR) to jedno z najbardziej przydatnych narzędzi do diagnozowania aplikacji Java na produkcji. Rejestruje informacje o zużyciu CPU, garbage collection, wątkach, alokacjach, blokadach, I/O oraz wielu innych zdarzeniach JVM przy stosunkowo niskim narzucie.

Jednak nagranie JFR może również zawierać informacje o tym, jak JVM została uruchomiona i skonfigurowana, w tym argumenty wiersza poleceń, zmienne środowiskowe oraz właściwości systemu (system properties).

Może to stanowić problem z punktu widzenia bezpieczeństwa, ponieważ wartości te mogą zawierać poufne dane, takie jak hasła, klucze API, tokeny dostępu czy poświadczenia.

Na przykład wyobraź sobie uruchomienie aplikacji w następujący sposób:

$ export ACCESS_TOKEN=SECRET_TOKEN
$ java -XX:StartFlightRecording:filename=dump.jfr \
       -Xmx2G \
       -Djavax.net.ssl.keyStorePassword=SECRET_PASSWORD \
       -jar application.jar \
      --dbpassword ANOTHER_SECRET_PASSWORD

Przed Javą 27 te poufne wartości mogły pojawiać się bezpośrednio wewnątrz nagrania JFR poprzez zdarzenia takie jak jdk.InitialEnvironmentVariable, jdk.InitialSystemProperty i jdk.JVMInformation.

Staje się to szczególnie problematyczne, gdy pliki .jfr są udostępniane innym programistom, dołączane do zgłoszeń serwisowych lub przesyłane do zewnętrznych systemów w celu analizy.

JEP 536 rozwiązuje ten problem, wprowadzając redagowanie danych bezpośrednio w procesie (in-process data redaction).

Zamiast zapisywać poufne informacje w nagraniu i oczyszczać plik po fakcie, JFR identyfikuje i redaguje poufne wartości zanim zostaną zapisane w nagraniu.

Java 27 wprowadza dwie nowe pod-opcje do -XX:FlightRecorderOptions:

redact-key
redact-argument

redact-key służy do identyfikowania poufnych zmiennych środowiskowych i właściwości systemowych, podczas gdy redact-argument dotyczy argumentów wiersza poleceń.

JFR posiada domyślne filtry redagowania zarówno dla argumentów wiersza poleceń, jak i par klucz-wartość, takich jak zmienne środowiskowe i właściwości systemowe.

Jeśli nie określono ani redact-key, ani redact-argument, automatycznie stosowane są wbudowane filtry. Obejmują one powszechnie używane poufne słowa kluczowe, takie jak hasła (passwords), sekrety (secrets), tokeny (tokens), poświadczenia (credentials), klucze prywatne (private keys), klucze API (API keys) i sekrety klienta (client secrets).


Język

JEP 532 : Typy prymitywne w wzorcach (Patterns), instanceof i switch (Piąty Preview)

JEP 532 kontynuuje prace nad rozszerzeniem dopasowywania wzorców (pattern matching) w Javie na typy prymitywne.

Do tej pory pattern matching był kojarzony głównie z typami referencyjnymi. Ta funkcja pozwala również typom prymitywnym brać udział w dopasowywaniu wzorców.

Na przykład:

int value = 100;
if (value instanceof byte b) {
  System.out.println("Fits in a byte: " + b);
}

Wzorzec dopasowuje się tylko wtedy, gdy konwersja jest dokładna, co oznacza, że żadne informacje nie zostają utracone. Na przykład 100 pasuje do byte, podczas gdy 1000 już nie.

Funkcja ta rozszerza również konstrukcję switch o obsługę wszystkich typów prymitywnych, w tym long, float, double i boolean:

long value = 42L;
String result = switch (value) {
  case 0L -> "zero";
  case 42L -> "the answer";
  default -> "other";
};

Wzorce prymitywne mogą być również stosowane bezpośrednio w etykietach case:

Object value = 42;
switch (value) {
  case byte b -> System.out.println("byte: " + b);
  case int i -> System.out.println("int: " + i);
  default -> System.out.println("other");
}

JEP 532 to piąty preview tej funkcji, po JEP 455, 488, 507 oraz 530.

Java 27 nie wprowadza zmian w języku w porównaniu z Javą 26; funkcja pozostaje w fazie preview, aby zebrać dodatkowe opinie przed jej sfinalizowaniem.


API

JEP 527 : Post-kwantowa hybrydowa wymiana kluczy dla TLS 1.3

JEP 527 wzmacnia TLS 1.3 przed przyszłymi atakami ze strony komputerów kwantowych poprzez wprowadzenie hybrydowych algorytmów wymiany kluczy.

Pomysł polega na połączeniu tradycyjnego algorytmu opartego na krzywych eliptycznych z post-kwantowym algorytmem ML-KEM. Chroni to przed zagrożeniem typu „harvest now, decrypt later” (przechwytuj teraz, odszyfruj później), w którym zaszyfrowany ruch jest gromadzony dzisiaj i potencjalnie odszyfrowany w przyszłości za pomocą komputerów kwantowych.

Java 27 wprowadza trzy schematy hybrydowe: X25519MLKEM768, SecP256r1MLKEM768 oraz SecP384r1MLKEM1024.

X25519MLKEM768, który łączy X25519 + ML-KEM-768, jest włączony domyślnie. Aplikacje korzystające ze standardowych API javax.net.ssl mogą zatem korzystać z ochrony post-kwantowej bez konieczności modyfikacji kodu, o ile nie nadpisują domyślnych nazwanych grup TLS (named groups).

Obsługiwane grupy można nadal dostosowywać za pomocą jdk.tls.namedGroups lub SSLParameters#setNamedGroups.

Dzięki temu JEP 527 sprawia, że aplikacje Java są domyślnie bardziej gotowe na erę post-kwantową, przy jednoczesnym zachowaniu kompatybilności z istniejącą infrastrukturą TLS.

JEP 531 : Leniwe stałe (Lazy Constants) (Trzeci Preview)

Leniwe stałe (Lazy Constants) zapewniają prosty sposób na inicjalizację wartości dopiero wtedy, gdy jest ona po raz pierwszy potrzebna, pozwalając jednocześnie JVM traktować tę wartość jako prawdziwą stałą i stosować optymalizacje, takie jak zwijanie stałych (constant folding).

Przykład:

static final LazyConstant LOGGER = LazyConstant.of(Logger::create);
Logger logger = LOGGER.get();

Dostawca (supplier) jest ewaluowany co najwyżej raz z sukcesem, w sposób bezpieczny dla wątków (thread-safe), przy pierwszym wywołaniu get().

Java 27 przynosi dwie główne zmiany w porównaniu z poprzednim preview:

  • Usunięto isInitialized() oraz orElse().
  • Leniwe kolekcje zostały rozszerzone o Set.ofLazy(...), obok istniejącej już obsługi leniwych List i Map.

JEP 531 pozostaje API w fazie preview w Javie 27.

JEP 533 : Wielowątkowość strukturalna (Structured Concurrency) (Siódmy Preview)

Wielowątkowość strukturalna (Structured Concurrency) traktuje grupę powiązanych zadań współbieżnych jako pojedynczą jednostkę pracy, co upraszcza anulowanie, obsługę błędów oraz obserwowalność.

Przy użyciu StructuredTaskScope podzadania są tworzone (forked) i łączone (joined) w ramach dobrze zdefiniowanego zakresu (scope):

try (var scope = StructuredTaskScope.open()) {
    Subtask<String> user  = scope.fork(() -> findUser());
    Subtask<Integer> order = scope.fork(() -> fetchOrder());

    scope.join(); // Czeka na zakończenie podzadań
    return new Response(user.get(), order.get());
}

Java 27 dopracowuje głównie obsługę wyjątków. StructuredTaskScope i Joiner przenoszą teraz typ wyjątku, jaki może rzucić join(), sprawiając, że kontrakt jest jawny na etapie kompilacji.

Standardowe joinery powodują teraz, że join() rzuca dobrze znany ExecutionException zamiast specyficznego dla preview FailedException. Usunięto również Joiner.awaitAll().

JEP 533 pozostaje API w fazie preview w Javie 27.

JEP 537 : Vector API (Dwunasta inkubacja)

Vector API pozwala programistom wyrażać obliczenia SIMD bezpośrednio w Javie, umożliwiając JVM ich kompilację do zoptymalizowanych wektorowych instrukcji CPU, takich jak AVX czy NEON.

Na przykład:

var va = FloatVector.fromArray(SPECIES, a, 0);
var vb = FloatVector.fromArray(SPECIES, b, 0);
var result = va.mul(vb).add(va);

Zamiast przetwarzać jedną wartość na raz, CPU może przetwarzać wiele wartości równolegle za pomocą rejestrów wektorowych.

JEP 537 to dwunasta inkubacja tego API i nie wprowadza istotnych zmian w implementacji w porównaniu z niedawnymi wydaniami.

Vector API pozostaje w fazie inkubacji, oczekując na niezbędne funkcja z Projektu Valhalla. Gdy staną się one dostępne, przewiduje się przejście API z fazy Inkubatora do Preview.

JEP 538 : Kodowanie PEM obiektów kryptograficznych (Trzeci Preview)

JEP 538 zapewnia standardowe Java API do kodowania i dekodowania kluczy kryptograficznych, certyfikatów i list CRL w formacie PEM, pozwalając uniknąć ręcznego parsowania i formatowania Base64.

API jest zbudowane głównie wokół PEMEncoder oraz PEMDecoder:

String pem = PEMEncoder.of().encodeToString(publicKey);
PublicKey key = PEMDecoder.of().decode(pem, PublicKey.class);

Klucze prywatne mogą być również szyfrowane i odszyfrowywane bezpośrednio za pomocą tego API.

W porównaniu z Javą 26 główne zmiany to:

  • Nazwa DEREncodable została zmieniona na BinaryEncodable.
  • PEM jest teraz zwykłą klasą zamiast rekordem.
  • EncryptedPrivateKeyInfo zyskuje obsługę pobierania KeyPair.
  • Nowy wyjątek CryptoException reprezentuje błędy przetwarzania kryptograficznego.

JEP 538 pozostaje API w fazie preview w Javie 27.


Podsumowanie

Java 27 kontynuuje stabilną ewolucję platformy, kładąc duży nacisk na wydajność, efektywność pamięciową, bezpieczeństwo i produktywność programistów.

To wydanie udostępnia domyślnie kilka ważnych usprawnień, w tym skompaktowane nagłówki obiektów (Compact Object Headers), G1 jako domyślny garbage collector we wszystkich środowiskach, silniejsze post-kwantowe bezpieczeństwo TLS oraz bezpieczniejsze nagrania JFR.

Jednocześnie funkcje takie jak Structured Concurrency, Lazy Constants, wzorce prymitywne, PEM API i Vector API nadal dojrzewają poprzez fazy preview i inkubacji.

Java 27 nie jest wydaniem LTS, ale wyraźnie pokazuje, w jakim kierunku zmierza platforma: wydajniejsza JVM, silniejsze domyślne ustawienia bezpieczeństwa i prostszy model programowania dla nowoczesnych aplikacji w Javie.

Czy Java 27 jest wydaniem z długoterminowym wsparciem (LTS)?

Nie, Java 27 to standardowe wydanie z 6-miesięcznym okresem wsparcia. Aktualnym wydaniem LTS pozostaje Java 25. Java 27 jest idealna do testowania usprawnień wydajnościowych i nowych funkcji przed kolejnym wydaniem LTS.

Jaki jest główny wpływ Compact Object Headers (JEP 534)?

Compact Object Headers zmniejszają nagłówki obiektów z 96 bitów do 64 bitów na 64-bitowych architekturach JVM. Zmniejsza to ślad pamięciowy domyślnie, bez konieczności używania jawnych flag JVM w Javie 27.

Dlaczego G1 GC jest teraz włączony w środowiskach z ograniczeniami (JEP 523)?

Ślad pamięciowy i przepustowość G1 uległy znacznej poprawie w ostatnich wydaniach. Serial GC nie jest już automatycznie uruchamiany na systemach z jednym CPU lub małą ilością pamięci, choć pozostaje dostępny za pomocą -XX:+UseSerialGC.

Jak działa redagowanie danych w procesie w JFR (JEP 536)?

JFR redaguje poufne parametry (takie jak hasła, klucze i tokeny) bezpośrednio w pamięci przed ich zapisaniem do nagrania .jfr, co zapobiega przypadkowym wyciekom podczas udostępniania logów diagnostycznych.

Czy muszę zaktualizować swój kod, aby używać Post-Kwantowego TLS 1.3 (JEP 527)?

Nie. Hybrydowy algorytm wymiany kluczy X25519MLKEM768 jest domyślnie włączony dla połączeń TLS 1.3, oferując ochronę odporną na komputery kwantowe „out of the box” dla standardowych aplikacji TLS w Javie.