Powody przejścia do Java 25

Java 25 jest wydaniem z długoterminowym wsparciem (LTS), co czyni je naturalnym wyborem dla zespołów korzystających obecnie z Javy 8, 11, 17 lub 21. Każda wersja LTS otrzymuje lata aktualizacji i poprawek zabezpieczeń, dlatego przejście na Java 25 zapewnia, że aplikacje są obsługiwane, bezpieczne i mogą korzystać z najnowszych ulepszeń wydajności i języka.

Pytanie nie jest , jeśli należy przejść do nowszej wersji LTS, ale kiedy. Tym dłużej czekasz, tym więcej zmian kumuluje się między bieżącą wersją a następną obsługiwaną. Przejście na Javę 25 przynosi wyraźne korzyści, a zaplanowanie migracji raczej wcześniej niż później zmniejsza ryzyko.

Od Java 8 każda wersja dodała funkcje i ulepszenia. Istnieją zauważalne dodatki i modyfikacje interfejsu API wraz z ulepszeniami czasu uruchamiania, przepływności, użycia pamięci, skalowalności i produktywności deweloperów. W tym artykule przedstawiono najbardziej wpływowe zmiany, koncentrując się na wersjach Java dostarczanych od czasu wydania Java 11 LTS: Java 17, Java 21 i Java 25.

Przejście do Java 25

Możesz przejść do Java 25 w sposób krokowy. Kod opracowany i skompilowany ze starszym zestawem JDK może być zwykle uruchamiany na Java 25 bez konieczności ponownego kompilowania. Podobnie jak w przypadku każdej dużej aktualizacji, zwróć uwagę na usunięte interfejsy API, pakiety oznaczone jako przestarzałe, wykorzystywanie wewnętrznych interfejsów API oraz zmiany domyślnego zachowania, zwłaszcza w obszarze odśmiecania pamięci.

Jeśli przechodzisz z wersji Java 8 lub 11, zacznij od przewodnika przejście z Java 8 do Java 11, aby uwzględnić największy zestaw niekompatybilnych zmian, a następnie przejdź dalej do Java 17, 21 i 25. Jeśli korzystasz już z Javy 17 lub 21, migracja do Javy 25 jest zazwyczaj mniej znacząca, ponieważ system modułów i większość zmian w platformie masz już za sobą.

Tip

Modernizacja usługi GitHub aplikacja Copilot może pomóc ocenić aplikację, zaplanować uaktualnienie i automatycznie zastosować zmiany kodu. Obsługuje uaktualnienia między Java wersjami 8, 11, 17, 21 i 25, kompiluje i testuje projekt po każdej zmianie i pomaga skorygować zmiany zachowania opisane w dalszej części tego artykułu.

Tip

Flagi JVM, które zostały dostrojone dla starszego zestawu JDK, mogą stać się przestarzałe, usunięte lub nieoptymalne w Java 25. Zamiast zachowywać przestarzałe ustawienia, możesz pozwolić, aby program Azure Command Launcher for Java (jaz) automatycznie zastosował flagi JVM dostosowane do wersji JDK oraz zasobów kontenera lub maszyny wirtualnej. Zastąp polecenie java poleceniem jaz w skrypcie uruchamiania lub użyj Dockerfile, aby skorzystać.

Zmiany wysokiego poziomu od Java 11

Ta sekcja nie wylicza wszystkich zmian wprowadzonych od Java 8. Podkreśla zmiany, które mają największy wpływ na wydajność, skalowalność, diagnostykę, produktywność i zabezpieczenia. Większość z tych funkcji dotarła do wersji Java 17, 21 i 25, a teraz jest częścią planu bazowego LTS dostępnego z Java 25. Każda funkcja zawiera informacje o wersji Java, w której została zintegrowana.

Skalowalność za pomocą wątków wirtualnych

Wątki wirtualne [1] to lekkie wątki zarządzane przez maszynę wirtualną JVM, a nie system operacyjny, które znacznie zmniejszają koszty zapisu i uruchamiania aplikacji współbieżnych o wysokiej przepływności. Dzięki wątkom wirtualnym można pisać kod w prostym modelu: jeden wątek na żądanie, a jednocześnie skalować aplikację do obsługi dużej liczby współbieżnych operacji, co sprawdza się idealnie w przypadku mikrousług intensywnie korzystających z operacji we/wy oraz obciążeń typu żądanie–odpowiedź.

Wątki wirtualne zostały oficjalnie wprowadzone w Javie 21. W Javie 24 usunięto kluczowe ograniczenie, umożliwiając wątkom wirtualnym synchronizację bez przypinania ich do wątków nośnych [2], co poprawia skalowalność kodu korzystającego z bloków synchronized.

Współbieżność strukturalna i wartości o określonym zasięgu

Wartości o zakresie [3] zapewniają bezpieczny, wydajny sposób udostępniania niezmiennych danych w wątkach i między nimi, w tym wątków wirtualnych. Stanowią nowoczesną alternatywę dla zmiennych lokalnych dla wątku, która dobrze sprawdza się w modelu jednego wątku na zadanie.

Współbieżność strukturalna [4] traktuje grupy powiązanych współbieżnie wykonywanych zadań jako pojedynczą jednostkę pracy, co upraszcza obsługę błędów i anulowanie. Po raz pierwszy zaprezentowana w wersji zapoznawczej w Javie 21, nadal się rozwija i dobrze współgra z wątkami wirtualnymi.

Produktywność języka

Seria ulepszeń języka dostarczanych w Java od 14 do Java 25 sprawia, że kod jest bardziej zwięzły, bezpieczniejszy i łatwiejszy do odczytania:

  • Wyrażenia switch [5] (Java 14) pozwalają switch zwracać wartość i korzystać z czytelniejszej składni strzałkowej.
  • Dopasowywanie wzorców w przypadku instanceof [6] (Java 16) eliminuje potrzebę jawnego rzutowania po sprawdzeniu typu.
  • Rekordy [7] (Java 16) modelują niezmienne dane jako transparentne nośniki dla ustalonego zestawu wartości, redukując ilość kodu szablonowego.
  • Zapieczętowane klasy [8] (Java 17) umożliwiają kontrolowanie klas, które mogą rozszerzać lub implementować typ.
  • Bloki tekstowe [9] (Java 15) upraszczają literały ciągu wielowierszowego.
  • Dopasowywanie wzorca dla switch [10] (Java 21) i wzorce rekordów [11] (Java 21) umożliwiają wyrażanie złożonej logiki warunkowej i destrukcji danych wyraźnie i bezpiecznie.
  • Kolekcje sekwencyjne [12] (Java 21) dodają jednolity interfejs API dla kolekcji ze zdefiniowaną kolejnością spotkań, w tym dostępem do pierwszych i ostatnich elementów.
  • Nienazwane zmienne i wzorce [13] (Java 22) umożliwiają jawne oznaczenie nieużywanych zmiennych i składników wzorca.
  • Deklaracje importu modułu [14] (Java 25) umożliwiają zaimportowanie wyeksportowanych pakietów całego modułu z pojedynczą deklaracją.
  • Kompaktowanie plików źródłowych i głównych metod wystąpienia [15] (Java 25) zmniejsza ceremonię wymaganą dla małych programów, co sprawia, że Java łatwiejsze do nauki i szybszego tworzenia prototypów.
  • Elastyczne treści konstruktorów [16] (Java 25) pozwalają wykonywać instrukcje przed wywołaniem super(...) lub this(...), co usprawnia walidację i inicjalizację.

Wydajność i uruchamianie

Kilka zmian środowiska uruchomieniowego poprawia przepływność, zużycie pamięci i czas uruchamiania:

  • Kompaktowe nagłówki obiektów [17] (Java 25) zmniejszają rozmiar nagłówków obiektów na platformach 64-bitowych. To zmniejszenie obniża zużycie pamięci sterty i może poprawić wydajność w przypadku obciążeń intensywnie korzystających z alokacji.
  • Współdzielenie danych klas (CDS) skraca czas uruchamiania dzięki mapowaniu zarchiwizowanych klas do pamięci w czasie wykonywania. Domyślne archiwa usługi CDS [18] (Java 12) i dynamiczne archiwa usługi CDS [19] (Java 13) ułatwiają wdrażanie tej funkcji bez ręcznych przebiegów trenowania.
  • Ładowanie i łączenie klas wykonywane z wyprzedzeniem [20] (Java 24), wraz z ergonomią wiersza poleceń wykonywaną z wyprzedzeniem [21] (Java 25) oraz profilowaniem metod wykonywanym z wyprzedzeniem [22] (Java 25), skracają czas uruchamiania i dochodzenia do pełnej wydajności dzięki ponownemu wykorzystaniu wyników pracy zapisanych w archiwum aplikacji. Te funkcje są częścią inicjatywy Project Leyden mającej na celu przyspieszenie uruchamiania Javy.

Te ulepszenia są szczególnie przydatne w przypadku obciążeń natywnych dla chmury i bezserwerowych, dzięki którym szybkie uruchamianie i niewielkie zużycie danych przekładają się bezpośrednio na lepsze skalowanie i niższe koszty.

Zbieranie śmieci

Java 25 jest dostarczana z dojrzałymi kolektorami odśmiecania pamięci o krótkich pauzach, odpowiednimi do szerokiego zakresu obciążeń:

  • ZGC [23] (Java 15) i Shenandoah [24] (Java 15) to gotowe do wdrożenia produkcyjnego kolektory pamięci, zaprojektowane z myślą o krótkich czasach wstrzymania w przypadku dużych stert.
  • G1GC pozostaje domyślnym modułem zbierającym i nadal otrzymuje ulepszenia, w tym przypinanie regionu [25] (Java 22) w celu zapewnienia bezproblemowej interakcji z kodem natywnym.
  • Generacja ZGC [26] (Java 21) zwiększa wydajność dzięki utrzymywaniu oddzielnych pokoleń. Od Java 23, ZGC działa w trybie generowania domyślnie [27], a tryb niegeneracyjny został usunięty w Java 24.
  • Generacyjny Shenandoah [28] (Java 25) dodaje tryb generacyjny do kolektora Shenandoah, aby poprawić przepływność i odporność przy presji pamięci.

Maszyny JVM ustawiają wartości domyślne GC dla średniego przypadku użycia. Dostosuj te ustawienia domyślne i inne ustawienia GC, aby zoptymalizować przepływność lub opóźnienie zgodnie z wymaganiami aplikacji.

Tip

Domyślny moduł odśmiecania pamięci i wiele domyślnych ustawień JVM różni się w różnych wersjach Java, więc ustawienia dostosowane do Java 8 lub 11 mogą nie być już optymalne dla Java 25. Azure Command Launcher for Java (jaz) automatycznie odczytuje limity pamięci i CPU cgroup kontenera oraz stosuje flagi JVM dostosowane do wersji JDK i środowiska.

Diagnostyka i możliwość obserwacji

Ulepszono diagnostykę w różnych wersjach, zarówno w języku, jak i w narzędziu Java Flight Recorder (JFR):

  • Przydatne wyjątki NullPointerException [29] (Java 14) precyzyjnie wskazują, która zmienna miała wartość null, co przyspiesza debugowanie.
  • Przesyłanie strumieniowe zdarzeń JFR [30] (Java 14) umożliwia narzędziom ciągłe używanie danych profilowania i diagnostyki, a nie z pliku zrzutu.
  • Profilowanie czasu CPU w JFR [31] (Java 25) wprowadza eksperymentalne profilowanie metod oparte na czasie CPU w systemie Linux.
  • Kooperacyjne próbkowanie JFR [32] (Java 25) poprawia stabilność próbkowania stosu.
  • Chronometraż i śledzenie metody JFR [33] (Java 25) umożliwia śledzenie określonych metod bez modyfikowania kodu aplikacji.

Zabezpieczenia i kryptografia

Java 25 wzmacnia stan zabezpieczeń platformy, w tym przygotowanie do świata po kwantowego:

  • Edwards-Curve algorytm podpisu cyfrowego (EdDSA) [34] (Java 15) dodaje nowoczesny schemat sygnatur o wysokiej wydajności.
  • Interfejs API mechanizmu hermetyzacji kluczy [35] (Java 21) udostępnia standardowy interfejs API dla algorytmów KEM.
  • Kryptografia odporna na ataki kwantowe wprowadza standardowe implementacje mechanizmu enkapsulacji klucza opartego na kratkach modularnych (ML-KEM) [36] (Java 24) oraz algorytmu podpisu cyfrowego (ML-DSA) [37] (Java 24).
  • API funkcji wyprowadzania kluczy [38] (Java 25) udostępnia standardowy interfejs API funkcji wyprowadzania kluczy.

Współdziałanie natywne

Interfejs API funkcji obcej i pamięci [39] (Java 22) zapewnia bezpieczny, wydajny i czysty Java sposób wywoływania bibliotek natywnych i uzyskiwania dostępu do pamięci natywnej. To nowoczesny zamiennik Java Native Interface (JNI), który ogranicza ilość kodu szablonowego i zwiększa bezpieczeństwo.

Narzędzia i biblioteki

Kilka dodatków usprawnia codzienne programowanie i zmniejsza potrzebę korzystania z narzędzi innych firm:

  • Narzędzie do tworzenia pakietów (jpackage) [40] (Java 16) tworzy natywne instalatory i pakiety dla aplikacji Java.
  • Prosty serwer sieci Web [41] (Java 18) zapewnia minimalny statyczny serwer HTTP do tworzenia prototypów i testowania.
  • Ulepszone generatory liczb pseudorandom [42] (Java 17) dodają nowe interfejsy i implementacje do generowania liczb losowych.

Zmiany w zachowaniu, które należy uwzględnić w planach

Niektóre zmiany od Java 11 zmieniają zachowanie domyślne, dlatego przed uaktualnieniem przejrzyj je:

  • Silna hermetyzacja elementów wewnętrznych JDK [43] (Java 17) domyślnie blokuje refleksyjny dostęp do większości wewnętrznych API. Kod lub biblioteki, które docierają do sun.* lub innych pakietów wewnętrznych, mogą wymagać aktualizacji.
  • UTF-8 domyślnie [44] (Java 18) sprawia, że UTF-8 staje się domyślnym kodowaniem znaków dla standardowych interfejsów API języka Java. Aplikacje, które opierały się na domyślnym zestawie znaków specyficznych dla platformy, mogą zachowywać się inaczej.
  • Oznaczenie finalizacji jako przestarzałej w celu usunięcia [45] (Java 18) sygnalizuje, że finalize() zostanie ostatecznie usunięta. Zmień na try-with-resources lub java.lang.ref.Cleaner.
  • Przygotowanie do uniemożliwienia dynamicznego ładowania agentów [46] (Java 21) ostrzega, gdy agent zostanie załadowany do uruchomionej maszyny wirtualnej JVM. Niektóre narzędzia do monitorowania i instrumentacji mogą wymagać zmian konfiguracji.

Tip

Modernizacja usługi GitHub aplikacja Copilot może pomóc w ocenie i skorygowaniu tych zmian zachowania automatycznie podczas uaktualniania.

Kontenery i chmura

Świadomość środowiska kontenerowego w JVM, wprowadzona z myślą o Dockerze i innych środowiskach uruchomieniowych kontenerów, jest nadal udoskonalana. JVM odczytuje ograniczenia dotyczące procesora i pamięci ustawione przez grupy kontrolne kontenera (cgroups) i odpowiednio dostosowuje rozmiar sterty oraz innych zasobów. W połączeniu z szybszym uruchamianiem, mniejszym rozmiarem i wątkami wirtualnymi Java 25 doskonale nadaje się do wdrożeń konteneryzowanych i bezserwerowych na platformie Azure.

Jeśli uruchamiasz obciążenia Java w kontenerach platformy Azure lub na maszynach wirtualnych, narzędzie Azure Command Launcher for Java (jaz) może zastosować zoptymalizowane pod kątem chmury domyślne ustawienia JVM odpowiednie dla danej wersji.

Następne kroki

References

[1] Oracle Corporation, "JEP 444: Virtual Threads". (Online). Dostępne: https://openjdk.org/jeps/444.

[2] Oracle Corporation, "JEP 491: Synchronizuj wątki wirtualne bez przypinania". (Online). Dostępne: https://openjdk.org/jeps/491.

[3] Oracle Corporation, "JEP 506: Wartości zakresowe." (Online). Dostępne: https://openjdk.org/jeps/506.

[4] Oracle Corporation, "JEP 453: Współbieżność strukturalna (wersja zapoznawcza)." (online). Dostępne: https://openjdk.org/jeps/453.

[5] Oracle Corporation, "JEP 361: Switch Expressions". (Online). Dostępne: https://openjdk.org/jeps/361.

[6] Oracle Corporation, „JEP 394: Pattern Matching for instanceof.” (online). Dostępne: https://openjdk.org/jeps/394.

[7] Oracle Corporation, "JEP 395: Records". (Online). Dostępne: https://openjdk.org/jeps/395.

[8] Oracle Corporation, "JEP 409: Sealed Classes". (Online). Dostępne: https://openjdk.org/jeps/409.

[9] Oracle Corporation, "JEP 378: Bloki tekstu". (Online). Dostępne: https://openjdk.org/jeps/378.

[10] Oracle Corporation, "JEP 441: Dopasowywanie wzorca dla przełącznika". (Online). Dostępne: https://openjdk.org/jeps/441.

[11] Oracle Corporation, "JEP 440: Record Patterns". (Online). Dostępne: https://openjdk.org/jeps/440.

[12] Oracle Corporation, "JEP 431: Sequenced Collections". (Online). Dostępne: https://openjdk.org/jeps/431.

[13] Oracle Corporation, "JEP 456: Nienazwane zmienne i wzorce". (Online). Dostępne: https://openjdk.org/jeps/456.

[14] Oracle Corporation, "JEP 511: Deklaracje importu modułów". (Online). Dostępne: https://openjdk.org/jeps/511.

[15] Oracle Corporation, "JEP 512: Compact Source Files and Instance Main Methods". (Online). Dostępne: https://openjdk.org/jeps/512.

[16] Oracle Corporation, "JEP 513: Elastyczne ciała konstruktorów". (Online). Dostępne: https://openjdk.org/jeps/513.

[17] Oracle Corporation, "JEP 519: Compact Object Headers". (Online). Dostępne: https://openjdk.org/jeps/519.

[18] Oracle Corporation, "JEP 341: Domyślne archiwa CDS". (Online). Dostępne: https://openjdk.org/jeps/341.

[19] Oracle Corporation, "JEP 350: Dynamic CDS Archives". (Online). Dostępne: https://openjdk.org/jeps/350.

[20] Oracle Corporation, "JEP 483: Ahead-of-Time Class Loading and Linking". (Online). Dostępne: https://openjdk.org/jeps/483.

[21] Oracle Corporation, "JEP 514: Ahead-of-Time Command-Line Ergonomics." (online). Dostępne: https://openjdk.org/jeps/514.

[22] Oracle Corporation, "JEP 515: Ahead-of-Time profilowanie metod." (Online). Dostępne: https://openjdk.org/jeps/515.

[23] Oracle Corporation, "JEP 377: ZGC: A Scalable Low-Latency Garbage Collector." (Online). Dostępne: https://openjdk.org/jeps/377.

[24] Oracle Corporation, "JEP 379: Shenandoah: A Low-Pause-Time Garbage Collector." (Online). Dostępne: https://openjdk.org/jeps/379.

[25] Oracle Corporation, "JEP 423: Przypinanie regionów dla G1" (Online). Dostępne: https://openjdk.org/jeps/423.

[26] Oracle Corporation, "JEP 439: Generational ZGC". (Online). Dostępne: https://openjdk.org/jeps/439.

[27] Oracle Corporation, "JEP 474: ZGC: Domyślny tryb generacyjny." (Online). Dostępne: https://openjdk.org/jeps/474.

[28] Oracle Corporation, "JEP 521: Generational Shenandoah". (Online). Dostępne: https://openjdk.org/jeps/521.

[29] Oracle Corporation, „JEP 358: Pomocne wyjątki NullPointerException.” (Online). Dostępne: https://openjdk.org/jeps/358.

[30] Oracle Corporation, "JEP 349: przesyłanie strumieniowe zdarzeń JFR". (Online). Dostępne: https://openjdk.org/jeps/349.

[31] Oracle Corporation, "JEP 509: JFR Profilowanie czasu procesora (eksperymentalne)." (online). Dostępne: https://openjdk.org/jeps/509.

[32] Oracle Corporation, "JEP 518: JFR Cooperative Sampling". (Online). Dostępne: https://openjdk.org/jeps/518.

[33] Oracle Corporation, "JEP 520: JFR Method Timing & Tracing". (Online). Dostępne: https://openjdk.org/jeps/520.

[34] Oracle Corporation, "JEP 339: Edwards-Curve Digital Signature Algorithm (EdDSA)." (Online). Dostępne: https://openjdk.org/jeps/339.

[35] Oracle Corporation, "JEP 452: Key Encapsulation Mechanism API". (Online). Dostępne: https://openjdk.org/jeps/452.

[36] Oracle Corporation, "JEP 496: Quantum-Resistant Module-Lattice-Based Key Encapsulation Mechanism." (Online). Dostępne: https://openjdk.org/jeps/496.

[37] Oracle Corporation, "JEP 497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm". (Online). Dostępne: https://openjdk.org/jeps/497.

[38] Oracle Corporation, "JEP 510: Key Derivation Function API". (Online). Dostępne: https://openjdk.org/jeps/510.

[39] Oracle Corporation, "JEP 454: Foreign Function & Memory API". (Online). Dostępne: https://openjdk.org/jeps/454.

[40] Oracle Corporation, "JEP 392: Packaging Tool". (Online). Dostępne: https://openjdk.org/jeps/392.

[41] Oracle Corporation, "JEP 408: Simple Web Server". (Online). Dostępne: https://openjdk.org/jeps/408.

[42] Oracle Corporation, "JEP 356: Ulepszone generatory liczb pseudolosowych." (online). Dostępne: https://openjdk.org/jeps/356.

[43] Oracle Corporation, "JEP 403: Silna hermetyzacja wewnętrznych elementów JDK." (Online). Dostępne: https://openjdk.org/jeps/403.

[44] Oracle Corporation, "JEP 400: UTF-8 by Default". (Online). Dostępne: https://openjdk.org/jeps/400.

[45] Oracle Corporation, "JEP 421: Oznaczenie finalizacji jako przestarzałej w celu usunięcia." (Online). Dostępne: https://openjdk.org/jeps/421.

[46] Oracle Corporation, "JEP 451: Prepare to Disallow the Dynamic Loading of Agents". (Online). Dostępne: https://openjdk.org/jeps/451.