Java 17 - co nowego?

14 września 2020 wydana została Java 17. Co nowego niesie ze sobą to wydanie? Jakie zmiany zostały ustabilizowane, a co wciąż jest ekperymentalne? Zapraszam na krótką wyprawę, na której chcę się przyjrzeć nowościom.
Oto dwa najważniejsze odnośniki:
- Java 17 API
- Java Language and Virtual Machine Specifications
- Java Language 17 Spec (PDF, HTML) - Preview feature: Pattern Matching for switch
- JVM Spec (PDF, HTML)
Warto przejrzeć New API since JDK 11 - podstronę w dokumentacji API - aby mieć przegląd zmian wprowadzonych w poprzednich wersjach.
Nowe wydanie Javy to idealny, wyczekany prezent (spóźniony o cztery dni, ale nie gniewam się) na moje urodziny. W końcu wydana została wersja Long Term Support - przez wielu developerów uznawana za stabilną.
Nowe wydanie
Na stronie JDK 17 znajduje się ostateczna lista JEP-ów, które wylądowały w nowym wydaniu.
O części z nich (np. o klasach “zapieczętowanych”) pisałam już we wpisach:
Jeśli ich jeszcze nie czytałaś/czytałeś, zapraszam! 😄
Lista zmian
Oto lista zmian w Javie 17 z odnośnikami do JEP-ów opisujących dokładniej daną zmianę. Nieco dalej przeczytasz o niektórych z tych zmian w dziennikarskim skrócie.
- Restore Always-Strict Floating-Point Semantics
- Enhanced Pseudo-Random Number Generators
- New macOS Rendering Pipeline
- macOS/AArch64 Port
- Deprecate the Applet API for Removal
- Strongly Encapsulate JDK Internals
- Pattern Matching for switch (Preview)
- Remove RMI Activation
- Sealed Classes
- Remove the Experimental AOT and JIT Compiler
- Deprecate the Security Manager for Removal
- Foreign Function & Memory API (Incubator)
- Vector API (Second Incubator)
- Context-Specific Deserialization Filters
Zobaczmy, co kryje się pod nimi kryje.
Garść szczegółów
Pattern matching w switch (preview)
To najciekawsza zmiana, która wprowadza dalsze rozszerzenia dopasowywania wzorca w instrukcji/wyrażeniu switch
:
- w labelkach
case
mogą pojawić się wzorce - można użyć wzorca
null
- wzorce mogą być “guarded”, czyli “strzeżone” przez wyrażenie boolowskie bądź posiadać nawiasy (wspomagające parsowanie)
Zamiast kodu
|
|
będzie można napisać:
|
|
Pokrycie
Switch musi pokryć wszystkie możliwe przypadki, musi więc albo posiadać wariant default
albo dotyczyć hierarchii klas sealed:
Ten kod nie będzie poprawny:
|
|
ale ten już tak:
|
|
podobnie jak ten:
|
|
Dopasowanie null-a
Jeśli w wyrażeniu/instrukcji switch pojawi się null
, można się do niego “dopasować”:
|
|
Wzorce - strażniki
Można testować pewne właściwości dopasowanego wzorca, przy czym logika testu może być zawarta w labelce case
:
|
|
Tego jeszcze nie ma, niestety.
Ale może będzie wkrótce. To JEP 405:
|
|
Odnośniki:
Nowy sposób renderowania Java 2D w systemie macOS
Zaimplementowano “potok renderujący” przy użyciu API Apple Metal, rezgnując z dotychczasowej implementacji wykorzystujacej przestarzałe API Apple OpenGL.
Może teraz, jak ktoś ma Maca, to mu się szybciej (i ładniej) wyrysuje na ekranie IntelliJ Idea albo Neatbeans?
Odnośnik:
JDK został przeportowany na macOS/AArch64
Apple zmienia CPU w swoich Mekintoszach z x86-64 na procesory swojego projektu oparte na architektrze ARM64. I potrzebuje na ten system portu macOS/AArch64.
Port na macOS będzie trzecim dla architektury AArch64 - istnieją już porty dla Linuksa i trwają prace nad portem dla Windowsa.
API apletów do kosza
Applet API - “deprecated” od wersji 9 - zostało oznaczone jako “deprecated for removal”. Dziś już chyba żadna przeglądarka nie wspiera apletów javowych.
Jak się chce robić coś, co widać w przeglądarce, to należy użyć JavaScript. Lub czegoś, co do JavaScriptu się kompiluje bądź transpiluje. Albo użyć WebGL.
Odnośniki:
Usunięcie RMI Activation
Mechanizm aktywacji zdalnych wywołań metod (RMI - Remote Method Invocation) został oznaczony do wyrzucenia w Javie 15, nikt nie zgłosił zastrzeżeń, więc teraz nastąpiło jego ostateczne zlikwidowanie.
Pakiet java.rmi.activation
znika, podobnie jak dotycząca go część dokumentacji, biblioteki, zbiór testów regresyjnych oraz demon rmid
wraz z dokumentacją.
Odnośniki:
Silne zamknięcie wewnętrznych pakietów JDK
Nie będzie można już użyć opcji --illegal-access
aby włączyć dostęp do wewnętrznych elementów JDK.
Pakiety sun.misc
oraz sun.reflect
będą wyeksportowane w module jdk.unsupported
i będą otwarte. Kod (np. zewnętrznych bibliotek) może wciąż mieć dotęp do ich niepublicznych elementów przez mechanizm refleksji.
Aby otworzyć dostęp do poszczególnych pakietów, wciąż można użyć opcji wiersza poleceń --add-opens
albo atrybutu Add-Opens
w manifeście pliku .jar.
Odnośniki:
Klasy sealed (klasy zapieczętowane)
Bardzo spodobało mi się tłumaczenie słowa “sealed” na język polski jako “zapieczętowane” (w artykule Adama Kukołowicza). Trochę długo się je wymawia, więc podejrzewam, że się nie przyjmie.
Implementacja w Javie 17 nie zmieniła się od wydania Javy 16, zmieniła jedynie status z preview feature
na wersję ustabilizowaną.
Odnośniki:
Przywrócenie semantyki “always-strict” dla liczb zmiennoprzecinkowych
To zmiana głównie kosmetyczna, polegająca na zaktualizowaniu specyfikacji języka (z którego zostanie usunięte rozróżnienie między wyrażeniami strict
i non-strict
, niewielkiej zmianie w HostSpot (żeby nie używał specjalnego trybu przy operacjach zmiennoprzecinkowych) i dodaniu do javac nowgo ostrzeżenia (o niepotrzebnym użyciu moryfikatora strictfp
).
W Javie 1.2 wprowadzono tryb non-strict
ze względu na to, że zbiór instrukcji koprocesora x86 nie pozwalał na efektywne generowanie kodu maszynowego w pewnych przypadkach - wymaganie strictfp
wiązało się z tym, że będzie generowana znaczna ilość dodatkowych instrukcji, ale za to obliczenia generujące underflow/overflow będą posiadały dokładnie takie same wyniki pośrednie na każdej platformie.
Jeśli dobrze zrozumiałam komentarz do tego JEP-a, to tryb domyślny, non-strict
, stworzono właśnie po to, aby kosztem pewnych nieścisłości (względem specyfikacji IEEE 754) ten dodatkowy kod nie był generowany, szczególnie jeśli nie trzeba zapewniać “przenośności” kodu między różnymi architekturami.
Jednak rozszerzenia zbioru instrukcji we współczenych procesorach (SSE2 w procesorze Pentium 4 i późniejszych) zapewniły, że operacje zmiennoprzecinkowe typu strict
są wspierane zupełnie naturalnie. Nie trzeba więc już utrzymywać specjalnego trybu non-strict
“chroniącego” przed overheadem, bo overheadu już nie ma (mniej więcej od dwudziestu lat).
Odnośniki:
Rozszerzenie generatorów liczb pseudolosowych (PRNG)
Ta zmiana wprowadza nowe interfejsy i implementacje generatorów liczb pseudolosowych.
Głównym celem zmiany jest umożliwienie użycia różnych generatorów w jednej aplikacji oraz wsparcie programowania potokowego (stream-based).
Obecnie klasa Random (i jej dwie podklasy, ThreadLocalRandom oraz SecureRandom) nie może być używana w kontekstach, w których używana jest inna klasa, SplittableRandom (która dzięki metodzie split
pozwala na wyforkowanie nowego generatora i przekazanie go do innego wątku).
Klasy te przed Javą 17 nie miały wspólnego interfejsu, więc po pierwsze, nie były wzajemnie “zastępowalne”, a po drugie nie można było użyć żadnej niezależnej implementacji generatorów w “przezroczysty” dla istniejącego kodu sposób.
W Javie 17 został wprowadzony interfejs RandomGenerator.
Implementują go klasy Random, SecureRandom, SplittableRandom, ThreadLocalRandom.
Została także dodana nowa klasa RandomGeneratorFactory<T extends RandomGenerator>
. Pozwala ona na utworzenie niezależnych generatorów na postawie nazwy algorytmu bądź utworzenie generatora posiadającego określone właściwości.
Odnośniki:
Kontekstowe filtry deserializacyjne
Oracle wprowadza mechanizm, dzięki któremu deserializacja danych z niezaufanych źródeł zostanie lepiej zabezpieczona.
Strumień bajtów to wektor ataku, w którym ktoś - przez odpowiednio staranne przygotowanie danych wysyłanych do odbiorcy i deserializowanych na jego systemie - może doprowadzić nie tylko do utworzenia i zainicjowania obiektów, lecz także do takich wywołań, które zmienią stan obiektów aplikacji, obiektów bibliotek czy nawet samego JVM-a.
Przeciwdziałanie “atakom przy użyciu deserializacji” polega na użyciu filtrów deserializacyjnych: interfejs java.io.ObjectInputFilter pozwala na napisanie kodu sprawdzającego strumień do deserializacji.
Odnośniki:
- JEP 415 - Context-Specific Deserialization Filters
- Serialization Filtering
- Secure coding guidelines fro Java SE
Inne aspekty wydania
Kompatybilność
Sześciomiesięczny cykl wydań Javy to niesamowite tempo, zważywszy wszystkie ograniczenia, jakie funkcjonują w świecie oprogramowania pisanego w tym języku. Przede wszystkim chodzi o konieczność zachowania kompatybilności wstecznej.
To naprawdę silna strona tego języka. No tak, trochę tutaj namieszało wprowadzenie modułów w Javie 9 - niektórzy szacują, że ponad 50% kodu bibliotek dostępnych w Mavenie nie było w 2009 roku gotowych na tę zmianę (Martijn Verburg wThe Register).
Licencja Free Use
Użycie wydania 17 Javy od Oracle (oracle jdk) możliwe jest pod nową licencją, nazwaną Free Use Licence, która pozwala na rozwijanie i dystrybucję kodu w Javie - pod warunkiem niepobierania opłat - dla wszystkich użytkowników (nie tylko do użytku osobistego i deweloperskiego)
Wsparcie
Wsparcie dla Javy 17 typu podstawowego “Premier Support” trwa do września 2028, wsparcie rozszerzone do września 2031 (Java 17 roadmap)
Java 18
Na horyzoncie jest już JDK 18 z dwoma JEP-ami:
Tutaj warto mieć rękę na pulsie i sprawdzać, co nowego szykują deweloperzy Javy w niedalekiej przyszłości.
Ten wpis jest częścią serii java.
- 2021-09-12 - Java 18: co nowego? - przegląd JEP-ów
- 2021-21-09 - Java 17 - RandomGenerator i spółka
- 2021-15-09 - Java 17 - co nowego?
- 2021-04-03 - Java 15 - czym są sealed classes?
- 2021-26-02 - Java 13 i 14: Bloki tekstowe i rekordy
- 2021-24-02 - Java 12 - wyrażenie switch (preview feature)
- 2021-23-02 - Java 11 - HTTP Client i uruchamianie jednoplikowych programów
- 2021-18-02 - Java 9 - co to jest JShell i dlaczego warto używać REPL-a w Javie
- 2021-12-02 - Java 10 - var, nowe metody w Optional, kolekcje "unmodifiable"
- 2021-11-02 - Java 9 - nowości w bibliotece
- 2021-10-02 - Java 9: czy mogę stworzyć z mojej aplikacji binarkę?
- 2021-10-02 - Java 9: praktyczny przykład - trzy moduły
- 2021-08-02 - Java 8: praktyczny przykład - przewidywanie kolejnej daty w serii