Lista nowości z Javy od wersji 22 do 25
W tym artykule przedstawię Ci, co zmieniło się w najnowszych wersjach Javy – od wersji 22 aż po 25, która jest kolejną wersją LTS (Long Term Support). Dzięki temu będziesz wiedział, czego możesz się spodziewać, pracując na konkretnej wersji i które nowości warto wprowadzić w swoich projektach.
To już trzeci wpis z serii omawiającej zmiany w języku programowania Java. Jeśli nie widziałeś poprzednich części, w których opisuję co się zmieniło we wcześniejszych wersjach, zapraszam do przeczytania:
Warto zaznaczyć, że Java 25, wydana we wrześniu 2025 roku, to kolejna wersja LTS po Java 21. Oznacza to, że otrzyma długoterminowe wsparcie i dla większości firm będzie to wersja, na którą warto migrować. Wersje pośrednie (22, 23, 24) to wydania krótkoterminowe, które wprowadziły wiele funkcji w trybie preview, z których część trafiła do stabilnej wersji właśnie w Java 25.
Java 22
Java 22 to pierwsze wydanie krótkoterminowe od czasu Java 21 LTS. Wersja ta przyniosła kilka interesujących funkcji, z których część była finalizowana po wcześniejszych preview, a część była dopiero wprowadzana jako wersje eksperymentalne.
Lista nowości:
- Unnamed Variables & Patterns (final, JEP 456) – Zmienne, których nie używamy, możemy zastąpić znakiem
_. - Statements before super(…) (preview, JEP 447) – Możliwość wykonywania instrukcji w konstruktorze jeszcze przed wywołaniem
super(). - Stream Gatherers (preview, JEP 461) – Możliwość tworzenia własnych, niestandardowych operacji pośrednich w Stream API.
- Launch Multi-File Source-Code Programs (final, JEP 458) – Uruchamianie programów składających się z wielu plików
.javabez wcześniejszej kompilacji. - Foreign Function & Memory API (final, JEP 454) – Nowy, bezpieczny sposób na łączenie Javy z bibliotekami C/C++.
Data wydania: 19 marzec 2024r.
Unnamed Variables & Patterns (final, JEP 456)
Po jednej rundzie preview w Java 21, funkcja Unnamed Variables & Patterns została ostatecznie sfinalizowana. Pozwala ona na użycie znaku podkreślenia _ jako zmiennej lub wzorca, którego po prostu nie używamy w kodzie.
Do tej pory często nazywaliśmy takie zmienne ignored, unused albo po prostu e, żeby IDE i statyczna analiza kodu nie świeciły na żółto. Teraz możemy jasno zaznaczyć, że dana zmienna jest nieużywana.
// Wcześniej - musieliśmy wymyślać nazwy
try {
int result = someRiskyOperation();
} catch (Exception ignored) {
// Wyjątek został przechwycony, ale nas nie interesuje
logError("Operacja nie powiodła się");
}
// Od Java 22 - używamy _
try {
int result = someRiskyOperation();
} catch (Exception _) {
logError("Operacja nie powiodła się");
}
Podobnie możemy robić w innych miejscach jak pętle, lambdy czy dekonstrukcje rekordów.
Niby drobna zmiana, ale wprowadziła wreszcie standard pod tego typu sytuacje.
Statements before super(…) (preview, JEP 447)
Od zawsze w Javie wymagane było, aby wywołanie super() lub this() było pierwszą instrukcją w konstruktorze. To ograniczenie często zmuszało do tworzenia pomocniczych metod statycznych lub dodatkowych konstruktorów.
Ta zmiana wprowadza możliwość umieszczenia kodu przed wywołaniem super(), o ile nie odwołuje się on do tworzonego obiektu. Dzięki temu możemy walidować parametry lub przygotowywać argumenty bezpośrednio w konstruktorze.
// Wcześniej - musieliśmy tworzyć pomocniczą metodę
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
super(validatePositive(value));
}
private static long validatePositive(long value) {
if (value <= 0) {
throw new IllegalArgumentException("Wartość musi być dodatnia");
}
return value;
}
}
// Od Java 22 (preview) - kod walidacji bezpośrednio w konstruktorze
public class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0) {
throw new IllegalArgumentException("Wartość musi być dodatnia");
}
super(value);
}
}
Stream Gatherers (preview, JEP 461)
Stream Gatherers to nowa operacja pośrednia w Stream API, która pozwala na tworzenie niestandardowych przekształceń strumieni. Do tej pory, jeśli potrzebowaliśmy bardziej zaawansowanych operacji niż te wbudowane (map, filter, reduce), musieliśmy albo kolekcjonować strumień do listy i wykonać operacje imperatywnie, albo stosować skomplikowane obejścia z collect.
Gatherers rozwiązują ten problem, wprowadzając metodę Stream::gather(Gatherer), która działa analogicznie do collect, ale dla operacji pośrednich.
Od teraz Java 22 dostarcza kilka wbudowanych gathererów w klasie java.util.stream.Gatherers:
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
// fold - agreguje elementy do jednego wyniku
Optional<Integer> sum = numbers.stream()
.gather(Gatherers.fold(() -> 0, (a, b) -> a + b))
.findFirst();
// scan - zwraca kolejne wyniki agregacji
numbers.stream()
.gather(Gatherers.scan(() -> 1, (a, b) -> a * b))
.forEach(System.out::println); // 1, 2, 6, 24, 120
// windowFixed - grupuje elementy w okna o stałym rozmiarze
numbers.stream()
.gather(Gatherers.windowFixed(2))
.forEach(System.out::println); // [1, 2], [3, 4], [5]
// windowSliding - tworzy przesuwane okna
numbers.stream()
.gather(Gatherers.windowSliding(3))
.forEach(System.out::println); // [1, 2, 3], [2, 3, 4], [3, 4, 5]
Do uruchomienia wymagane jest dodanie flagi --enable-preview ze względu na to, że jest to jest funkcjonalność preview.
Launch Multi-File Source-Code Programs (final, JEP 458)
Od Java 11 można było uruchamiać pojedyncze pliki źródłowe .java bezpośrednio, bez wcześniejszej kompilacji. Java 22 rozszerza tę funkcjonalność na programy składające się z wielu plików.
Wcześniej, aby uruchomić program z kilkoma klasami, musieliśmy najpierw skompilować wszystkie pliki:
# Wcześniej javac Main.java Helper.java java Main # Od Java 22 java Main.java
Launcher automatycznie znajdzie i skompiluje w pamięci wszystkie pliki .java w tym samym katalogu, które są potrzebne do uruchomienia programu.
Foreign Function & Memory API (final, JEP 454)
Po dwóch rundach jako inkubator (Java 17-18) i trzech rundach w preview (Java 19-21), Foreign Function & Memory API w końcu została sfinalizowana w Java 22.
API to zastępuje stary i problematyczny JNI (Java Native Interface), oferując bezpieczniejszy i wygodniejszy sposób na:
- Wywoływanie funkcji z bibliotek natywnych (C, C++, Rust)
- Bezpośredni dostęp do pamięci poza JVM
Przykład wywołania funkcji C++ z biblioteki matematycznej:
Załóżmy, że mamy prostą bibliotekę w C++ (math_lib.cpp), którą kompilujemy do pliku .dll lub .so. Kluczowe jest użycie extern "C", aby zapobiec zmianie nazw funkcji przez kompilator C++ (name mangling).
Kod C++ (math_lib.cpp):
extern "C" {
int add(int a, int b) {
return a + b;
}
}
Po skompilowaniu do biblioteki współdzielonej (libmathlib.so na Linux, mathlib.dll na Windows), możemy ją wywołać z Javy:
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
public class CppInterop {
public static void main(String[] args) throws Throwable {
// 1. Ładowanie biblioteki
System.loadLibrary("math_lib");
// 2. Szukanie funkcji 'add' i definiowanie jej sygnatury (int, int -> int)
Linker linker = Linker.nativeLinker();
SymbolLookup lookup = SymbolLookup.loaderLookup();
MethodHandle addHandle = linker.downcallHandle(
lookup.find("add").get(),
FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT)
);
// 3. Wywołanie funkcji natywnej
int result = (int) addHandle.invoke(10, 25);
System.out.println("Wynik z C++: " + result); // Wynik z C++: 35
}
}
Java 23
Java 23 to druga wersja krótkoterminowa od czasu Java 21 LTS. Wersja ta przyniosła kilka ciekawych nowości, w tym jedną, która nie przechodziła wcześniej przez preview – Markdown Documentation Comments.
Lista nowości:
- Markdown Documentation Comments (JEP 467) – Możliwość pisania Javadoca w Markdownie zamiast w HTML.
- Primitive Types in Patterns, instanceof, and switch (preview, JEP 455) – Pattern matching działa teraz także dla typów prostych (int, long itd.).
- Module Import Declarations (preview, JEP 476) – Importowanie całych modułów jedną linijką kodu.
- Implicitly Declared Classes and Instance Main Methods (third preview, JEP 477) – Dalsze upraszczanie wejścia w świat Javy (Hello World bez zbędnego boilerplate’u).
- Stream Gatherers (second preview, JEP 473) – Druga runda testowa dla nowej operacji pośredniej w strumieniach (bez zmian w API względem Javy 22).
Data wydania: 17 wrzesień 2024r.
Markdown Documentation Comments (JEP 467)
Jedna z najbardziej praktycznych nowości w Java 23 – możliwość pisania dokumentacji JavaDoc w formacie Markdown zamiast HTML i tagów JavaDoc. Co ciekawe, ta funkcja została sfinalizowana od razu, bez przechodzenia przez fazę preview.
Wcześniej pisanie dokumentacji było żmudne i wymagało znajomości HTML:
/**
* Returns a hash code value for the object.
* This method is supported for the benefit of hash tables such as those
* provided by {@link java.util.HashMap}.
* <p>
* The general contract of <code>hashCode</code> is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the <code>hashCode</code> method
* must consistently return the same integer.</li>
* <li>If two objects are equal according to the
* {@link #equals(Object)} method, then calling the
* <code>hashCode</code> method on each must produce the same result.</li>
* </ul>
*/
public int hashCode() { ... }
Od Java 23 możemy użyć Markdown (komentarze zaczynają się od ///):
/// Returns a hash code value for the object.
/// This method is supported for the benefit of hash tables such as those
/// provided by [java.util.HashMap].
///
/// The general contract of `hashCode` is:
///
/// - Whenever it is invoked on the same object more than once during
/// an execution of a Java application, the `hashCode` method
/// must consistently return the same integer.
/// - If two objects are equal according to the [equals][#equals(Object)]
/// method, then calling the `hashCode` method on each must produce
/// the same result.
public int hashCode() { ... }
Jest to zmiana raczej kosmetyczna, bo większość nowoczesnych IDE i tak potrafi bardzo dobrze formatować komentarze, więc czytelność zwykle nie stanowi problemu. Natomiast podczas pisania komentarzy różnica jest wyraźnie odczuwalna – Markdown pozwala robić to szybciej, wygodniej i bez przepychania się ze znacznikami HTML.

Primitive Types in Patterns, instanceof, and switch (preview, JEP 455)
Pattern Matching (Dopasowywanie wzorców) to jedna z najlepszych rzeczy, jakie trafiły do Javy w ostatnich latach. Miało jednak jedną wadę – działało tylko na obiektach. Nie mogliśmy użyć instanceof ani wzorców w switch dla typów prostych (np. int), chyba że opakowaliśmy je w Integer.
JEP 455 rozszerza pattern matching, pozwalając na używanie typów prymitywnych w instanceof i switch.
Teraz możemy używać instanceof z typami prymitywnymi:
int value = 100;
if (value instanceof byte b) {
System.out.println("Wartość mieści się w byte: " + b);
} else {
System.out.println("Wartość za duża dla byte");
}
Switch również został rozszerzony o wszystkie typy prymitywne:
// Wcześniej switch nie obsługiwał long, double, float
double price = 19.99;
switch (price) {
case 9.99 -> System.out.println("Promocja!");
case 19.99 -> System.out.println("Regularna cena");
case 29.99 -> System.out.println("Premium");
default -> System.out.println("Inna cena: " + price);
}
Możemy też łączyć to z pattern matching:
int number = 100_000;
switch (number) {
case byte b -> System.out.println("Mały: " + b);
case short s -> System.out.println("Średni: " + s);
case int i -> System.out.println("Normalny: " + i);
}
Module Import Declarations (preview, JEP 476)
Ta zmiana upraszcza importy w przypadku modułów, pozwalając na zaimportowanie wszystkich pakietów eksportowanych przez moduł za jednym razem.
Wcześniej, aby użyć klas z modułu java.base, musieliśmy importować każdy pakiet osobno:
import java.util.List; import java.util.Map; import java.util.Set; import java.io.IOException; import java.nio.file.Path;
Od Java 23 możemy zaimportować cały moduł:
import module java.base;
// Teraz mamy dostęp do wszystkich eksportowanych pakietów
List<String> list = new ArrayList<>();
Path path = Path.of("/tmp");
To szczególnie przydatne przy pracy z własnymi modułami lub w projektach edukacyjnych, gdzie chcemy szybko eksperymentować bez konieczności dodawania dziesiątek importów.
Implicitly Declared Classes and Instance Main Methods (third preview, JEP 477)
JEP 477 to kontynuacja projektu „torowania drogi” dla początkujących programistów w Javie. Funkcja ta, po raz trzeci w preview, znacząco upraszcza pisanie pierwszych programów bez konieczności rozumienia konstrukcji przeznaczonych dla dużych aplikacji.
Tradycyjny „Hello World” w Javie wymagał sporej wiedzy:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Od Java 23 (z flagą --enable-preview) możemy napisać po prostu:
void main() {
println("Hello, World!");
}
Tak, to naprawdę cały program! Kompilator automatycznie tworzy niejawną klasę wokół tej metody.
Co dokładnie się zmieniło w trzecim preview:
Automatyczne importy I/O – dostępne są proste metody do interakcji z konsolą:
void main() {
String name = readln("Podaj swoje imię: ");
println("Witaj, " + name + "!");
}
Automatyczne importy z java.base – wszystkie publiczne klasy i interfejsy z modułu java.base są dostępne bez importów. Nie trzeba już pisać import java.util.List;.
void main() {
List<String> names = List.of("Anna", "Jan", "Kasia");
println("Liczba osób: " + names.size());
}
Warto jeszcze dodać, że metoda main może być dość elastyczna:
// Bez parametrów
void main() { }
// Z parametrami
void main(String[] args) { }
// Nie musi być public ani static
void main() { }
// Można dodawać pola i metody
String greeting = "Cześć!";
void main() {
println(greeting);
}
String getGreeting() {
return greeting;
}
To spory krok w stronę uproszczenia nauki Javy. Początkujący mogą skupić się na samej logice programowania, zamiast od razu wpadać w bardziej zaawansowane tematy jak klasy, modyfikatory dostępu czy statyczne metody.
Stream Gatherers (second preview, JEP 473)
Wspomniane przy okazji Javy 22 Stream Gatherers w tej wersji przechodzą do drugiej fazy Preview. Co ważne, nie wprowadzono tutaj żadnych zmian w API względem poprzedniej wersji. Celem jest zebranie dodatkowych opinii od społeczności przed finalizacją tej funkcji. To dobra wiadomość – oznacza, że API jest stabilne i jeśli zacząłeś go używać w Javie 22, Twój kod nadal będzie działał.
Java 24
Jest to szczególne wydanie – zawiera aż 24 JEP-y, z których wiele to funkcje finalne, które wcześniej przechodziły przez kolejne rundy preview.
Lista nowości:
- Stream Gatherers (finalizacja, JEP 485) – Niestandardowe operacje pośrednie w strumieniach wchodzą do standardu.
- Scoped Values (czwarty preview, JEP 487) – Znaczne przyspieszenie czasu startu aplikacji (projekt Leyden).
- Flexible Constructor Bodies (trzeci preview, JEP 492) – Dalsze prace nad wydajnymi danymi kontekstowymi dla wątków wirtualnych.
- Ahead-of-Time Class Loading & Linking (JEP 483) – Jeszcze większa swoboda w konstruktorach (inicjalizacja pól przed
super).
Data wydania: 18 marzec 2025r.
Stream Gatherers (finalizacja, JEP 485)
Po dwóch rundach w preview (Java 22-23), Stream Gatherers zostały ostatecznie sfinalizowane w Java 24. Ta funkcja była już opisana w sekcji Java 22, ale teraz możemy z niej korzystać bez flagi --enable-preview.
Stream Gatherers to jeden z najbardziej praktycznych dodatków do Stream API od czasu wprowadzenia samego API w Java 8. Pozwala na tworzenie niestandardowych operacji pośrednich, które wykraczają poza możliwości standardowych map, filter czy reduce.
Funkcja jest w pełni gotowa do użycia w produkcji i stanowi doskonałe narzędzie do bardziej zaawansowanego przetwarzania strumieni.
Scoped Values (czwarty preview, JEP 487)
Scoped Values to alternatywa dla ThreadLocal, szczególnie przydatna przy pracy z wirtualnymi wątkami. Po raz czwarty w preview (Java 20-24), funkcja ta pozwala na dzielenie się niezmiennymi danymi w obrębie określonego zakresu.
// Definicja wartości zakresowej
private static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
public void handleRequest() {
// Uruchamiamy kod w "zakresie", gdzie REQUEST_ID ma wartość "req-123"
ScopedValue.where(REQUEST_ID, "req-123").run(() -> {
processOrder(); // Ta metoda (i jej dzieci) ma dostęp do REQUEST_ID
});
}
public void processOrder() {
System.out.println("Przetwarzanie ID: " + REQUEST_ID.get());
}
Główne zalety nad ThreadLocal:
- Niemutowalność – wartości nie można zmienić po ustawieniu
- Lepsze zarządzanie pamięcią – automatyczne czyszczenie po zakończeniu zakresu
- Idealne dla wirtualnych wątków – bez przecieków pamięci
Flexible Constructor Bodies (trzeci preview, JEP 492)
Kontynuacja JEP 447 z Java 22 (wcześniej „Statements before super”). W trzecim preview wprowadzono istotną zmianę – możliwość inicjalizacji pól przed wywołaniem konstruktora nadklasy.
public class User extends Person {
private final String email;
public User(String fullName, String rawEmail) {
// Możemy teraz inicjalizować pola przed super()!
this.email = rawEmail.toLowerCase().trim();
String[] parts = fullName.split(" ");
super(parts[0], parts[1]);
}
}
Ahead-of-Time Class Loading & Linking (JEP 483)
To nowość, która wywodzi się z Projektu Leyden. Głównym problemem Javy w środowiskach chmurowych (Serverless, Kubernetes) jest „zimny start”. JVM musi załadować tysiące klas, zweryfikować je, zlinkować i zoptymalizować, zanim aplikacja zacznie działać.
JEP 483 wprowadza możliwość utworzenia archiwum (pliku cache), które przechowuje stan maszyny wirtualnej po załadowaniu klas. Przy kolejnym uruchomieniu JVM „odtwarza” ten stan, zamiast budować go od nowa.
Jak to działa w praktyce?
1. Nagrywanie (Training Run) – Uruchamiasz aplikację w trybie treningowym. JVM zapisuje załadowane klasy do pliku.
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -jar my-app.jar
2. Generowanie cache – Tworzysz zoptymalizowane archiwum.
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot my-app.jar
3. Uruchamianie (Production Run) – Startujesz aplikację z użyciem cache. Czas startu może spaść o 40-50%!
java -XX:AOTCache=app.aot -jar my-app.jar
W przeciwieństwie do GraalVM Native Image, tutaj nadal korzystamy z pełnej, dynamicznej maszyny JVM (JIT, dynamiczne ładowanie klas), ale startujemy znacznie szybciej.
Java 25 (LTS)
Java 25 to kolejna wersja o długoterminowym wsparciu (LTS) po Java 21, co oznacza, że będzie otrzymywać aktualizacje i wsparcie przez co najmniej 5 lat. Dla firm i projektów długoterminowych jest to wersja, na którą warto migrować.
Wersja ta zawiera 18 JEP-ów, z czego 7 to funkcje sfinalizowane po wcześniejszych rundach preview/incubation. Co istotne, aż 9 z nich skupia się na wydajności i runtime.
Lista nowości:
- Scoped Values (final, JEP 506) – Nowoczesna alternatywa dla
ThreadLocalosiąga status standardu. - Flexible Constructor Bodies (final, JEP 513) – Koniec z restrykcyjnym
super()na początku konstruktora. - Compact Source Files and Instance Main Methods (final, JEP 512) – Uproszczony „Hello World” i luźne metody
mainwchodzą na stałe. - Stable Value API (preview, JEP 502) – Wprowadzenie typów wartościowych (Value Classes).
- Key Derivation Function API (final, JEP 510) – Nowe, standardowe API do kryptograficznych funkcji wyprowadzania kluczy (KDF).
- Primitive Types in Patterns (third preview, JEP 507) – Dalsze szlifowanie wzorców dla typów prostych.
- Module Import Declarations (preview, JEP 511) – Importowanie całych modułów (
import module) wchodzi w kolejną fazę testów.
Data wydania: 16 wrzesień 2025r.
Scoped Values (final, JEP 506)
Po jednej rundzie inkubacji (Java 20) i czterech rundach preview (Java 21-24), Scoped Values zostały ostatecznie sfinalizowane. Bardziej szczegółowo omawiałem to w ramach omawiania Java 24.
private static final ScopedValue<User> CURRENT_USER = ScopedValue.newInstance();
void handleRequest(User user) {
ScopedValue.where(CURRENT_USER, user).run(() -> {
processRequest();
// user dostępny w całym zakresie
});
// user już niedostępny - automatyczne czyszczenie
}
Flexible Constructor Bodies (final, JEP 513)
Po trzech rundach preview, możliwość wykonywania instrukcji przed wywołaniem super() została sfinalizowana. Możemy teraz naturalnie inicjalizować pola i walidować dane przed wywołaniem konstruktora nadklasy. Omawiałem bardziej szczegółowo w zmianach dla Java 22 i Java 24.
public class SecureContainer extends Container {
public SecureContainer(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException("Capacity must be positive");
if (capacity > 10_000) System.getLogger("app").log(Level.WARNING, "Large capacity alert");
super(capacity); // Wywołanie rodzica dopiero po weryfikacji
}
}
Compact Source Files and Instance Main Methods (final, JEP 512)
Po czterech rundach preview (Java 21–24) ta funkcja w końcu została sfinalizowana. Teraz prosty program można napisać dosłownie bez całej otoczki: bez klas, bez public static, bez importów. Java daje tu trochę oddechu od pełnego OOP i staje się znacznie bardziej przystępna dla początkujących. Samą zmianę omawiałem już przy okazji Java 23.
void main() {
println("Hello, Java 25!");
String name = readln("Jak masz na imię? ");
println("Witaj, " + name + "!");
}
Stable Value API (preview, JEP 502)
Nowe API pozwala tworzyć pola, które można ustawić tylko raz, ale nie muszą być inicjalizowane w momencie tworzenia obiektu. Dostajemy elastyczność zwykłych pól, a jednocześnie zachowujemy bezpieczeństwo, które do tej pory dawało final.
class ProductService {
private final StableValue<Properties> config = StableValue.of();
public void processOrder(Order order) {
Properties appConfig = config.orElseSet(() -> {
System.out.println("Ładowanie konfiguracji z pliku...");
return ConfigLoader.load("app.properties");
});
int maxRetries = Integer.parseInt(appConfig.getProperty("max.retries", "3"));
String endpoint = appConfig.getProperty("api.endpoint");
// Użycie w logice biznesowej
sendToApi(endpoint, order, maxRetries);
}
}
A co nam do daje w praktyce?
- Leniwa inicjalizacja z gwarancjami niezmienności
- JVM może traktować je jako stałe po inicjalizacji
- Lepsza optymalizacja niż zwykłe pola
Key Derivation Function API (final, JEP 510)
Po jednej rundzie preview (Java 24, JEP 478), API do funkcji wyprowadzania kluczy zostało sfinalizowane. Umożliwia bezpieczne generowanie kluczy kryptograficznych z haseł użytkowników.
import javax.crypto.KDF;
import javax.crypto.SecretKey;
import javax.crypto.spec.HKDFParameterSpec;
class ApiKeyGenerator {
public SecretKey generateApiKey(String userId, String masterSecret) throws Exception {
KDF kdf = KDF.getInstance("HKDF-SHA256");
// Wyprowadzenie unikalnego klucza API dla użytkownika
HKDFParameterSpec spec = HKDFParameterSpec.ofExtract()
.addIKM(masterSecret.getBytes())
.addSalt(userId.getBytes())
.thenExpand(("api-key-" + userId).getBytes(), 32);
SecretKey apiKey = kdf.deriveKey("AES", spec);
return apiKey;
}
}
// Użycie
ApiKeyGenerator generator = new ApiKeyGenerator();
SecretKey userApiKey = generator.generateApiKey("user123", "master-secret");
Standaryzuje podejście do KDF, eliminując potrzebę zewnętrznych bibliotek dla podstawowych operacji kryptograficznych.
Primitive Types in Patterns (third preview, JEP 507)
Kontynuacja funkcji z Java 23 – Java 24. Pattern matching dla typów prymitywnych w instanceof i switch wchodzi w trzecią rundę preview.
int value = 100;
switch (value) {
case byte b -> println("Byte: " + b);
case short s -> println("Short: " + s);
case int i -> println("Int: " + i);
}
Funkcja jest bliska finalizacji i prawdopodobnie stanie się stabilna w Java 26.
Podsumowanie
Java od wersji 22 do 25 przyniosła wiele istotnych zmian, które z pewnością warto poznać i wykorzystać w swoich projektach. Oto najważniejsze funkcjonalności wprowadzone z perspektywy programisty:
- Unnamed Variables & Patterns (Java 22) – Możliwość użycia znaku podkreślenia
_dla zmiennych, których nie potrzebujemy (np. w lambdach, blokachcatchczy przy dekonstrukcji rekordów). - Foreign Function & Memory API (Java 22) – Nowy standard bezpiecznej i wydajnej integracji z kodem natywnym (C/C++), który ostatecznie zastępuje przestarzałe JNI.
- Markdown Documentation Comments (Java 23) – Możliwość pisania dokumentacji Javadoc przy użyciu czytelnego Markdowna (
///) zamiast skomplikowanego HTML-a. - Primitive Types in Patterns (Java 23) – Pattern matching obsługuje teraz typy pierwotne (
int,double,byte) wswitchiinstanceof, eliminując zbędny boxing. - Stream Gatherers (Java 25) – Długo wyczekiwane rozszerzenie Stream API, umożliwiające tworzenie niestandardowych operacji pośrednich, takich jak
fold,scan,windowFixedczywindowSliding. - Flexible Constructor Bodies (Java 25) – Koniec ze sztucznymi blokadami – teraz możemy inicjalizować pola i wykonywać logikę w konstruktorze jeszcze przed wywołaniem
super(). - Scoped Values (Java 25) – Nowoczesna, lekka i wydajna alternatywa dla
ThreadLocal, zaprojektowana z myślą o wirtualnych wątkach. - Compact Source Files (Java 25) – Uproszczony start: wystarczy metoda
void main()bez konieczności deklarowania klasy i metod statycznych. - Key Derivation Function API (Java 25) – Nowe, ustandaryzowane API do kryptograficznego wyprowadzania kluczy (KDF), ułatwiające pracę z bezpieczeństwem aplikacji.
- Value API (Java 25 Preview) – Wprowadzenie obiektów wartościowych, które korzystają z głębokich optymalizacji maszyny wirtualnej JVM (brak tożsamości, płaska struktura w pamięci).
Następny wpis zostanie opublikowany przy okazji kolejnej wersji LTS, którą (na dzisiaj) ma być Java 29, zakładając, że wersje wychodzą co pół roku powinna pojawić się jakoś we wrześniu 2027.