Java 23 w praktyce

Jakie zmiany w języku i bibliotece standardowej są warte uwagi? Krótki przewodnik dla zabieganych programistów.
Java 23 w praktyce
Eksperymenty z palca
Dzięki wprowadzeniu w ostatnich wersjach importu modułów, niejawnie deklarowanych klas i metod main oraz uruchamianiu programu posiadającego wiele plików źródłowych możemy teraz wesoło eksperymentować z javą bez konieczności tworzenia projektu w gradle/maven oraz bez odpalania ciężkiego IDE.
- nie trzeba definiować żadnej klasy, wystarczy metoda
main(klasa zostanie utworzona niejawnie) - main nie musi mieć parametrów (jeśli nie potrzebujemy ich używać)
- main nie musi być
public static - można korzystać z innych plików (pod warunkiem, że są w nich zdefiniowane klasy publiczne)
- w niejawnych klasach (oraz w sesjach JShell uruchomionych z parametrem
--enable-preview) wszystkie publiczne klasy zjava.basesą automatycznie zaimportowane - dzięki nowej klasie
java.io.IO(która jest automatycznie zaimportowana) można używać metodyprintbez tego javovego “ogona”System.out.println
Bardzo mnie to cieszy - odpalam sobie neovima i zaczynam zabawę (btw, odkryłam ostatnio neovimcraft.com, polecam) . Wczoraj na przykład testowałam wypisywanie kolorowych napisów przy użyciu instrukcji sterujących do terminala. Oto pełna zawartość pliku Colors.java:
|
|
Do uruchomienia wystarczy polecenie
|
|
Używam małego skryptu jav, który dodałam do swojej $PATH i dzięki któremu mogę korzystać z uzupełniania nazw plików. Oto jav:
|
|

String Templates
W javie 23 zniknęły String Templates. Będę za nimi tęsknić. Mam nadzieję, że zostanie opracowana sensowna alternatywa dla dotychczas proponowanych ukośników.
Wątki wirtualne
O wątkach pisałam już jakiś czas temu (Virtual Threads w Javie 21) Pierwsze doniesienia z frontu wskazują na potrzebę mądrego yżywania synchornizacji: wątek wirtualy wchodzący do sekcji kodu synchronized zostaje przypięty (ang. pinned) do wątku “nosiciela” (carrier thread) i blokuje go (tj. wątek wirtualny nie może zostać “odmontowany”) - patrz: problem z biblioteką jsoup o diagnozowaniu pewnego problemu ze współbieznością) - co w przypadku serwerów obsługujących wiele połączeń może szybko doprowadzić do wykorzystania wszystkich dostępnych wątków platformowych bądź do znacznego ograniczenia wydajności systemu.
Strategie polecane do tego, aby zmniejszyć ryzyko pinningu:
- użycie
ReentrantLocksz pakietujava.util.concurrent.locks: pozwala na odmontowanie wątku wirtualnego gdy jest on zatrzymany na locku - przegląd kodu: zwracamy uwagę na to, aby synchronized nie był zbyt często używany
- diagnozowanie pinningu przy użyciu flagi
-Djdk.tracePinnedThreads=full
Scoped Values
O tym też napisałam co nieco w artykule Jeśli nie ThreadLocal to co? ScopedValue!. Java 23 to już trzecie “preview”: pojawiła się statyczna metoda ScopedValue.callWhere przyjmująca interfejs funkcyjny. Strukturalna współbieżność (structuredTaskScope) pozwala na elekganckie utworzenie drzewa wątków mających dostęp do niemutowalnych, ale nadpisywalnych w głębszych wywołaniach ScopedValues.
|
|
Structured Concurrency
ScopedValues doskonale sprawdzą się w sytuacji, gdy uruchamiane na wątkach wirtualnych zadania powinny mieć dostęp do zniennych “thread local” w bezpieczny sposób. Uruchamianie zadań przy pomocy strukturalnej współbieżności jeszcze nie doczekało się wielu przykładów użycia, więc kradnę przykład ze strony https://openjdk.org/jeps/480:
|
|
JavaDoc i Markdown
W Java 23 można używać komentarzy w markdown. Oto przykład:
|
|
Odnośniki mogą mieć tekst alternatywny; można używać tabel. I należy pamiętać o sekwencji unikowej podczas wypisywania nawaisów kwadratowych:
|
|
Patterns, rekordy i typy podstawowe
Java jest powoli wzbogacana możliwością użycia pattern matchingu. Jego niewątpliwą, choć nieczęsto podkreślaną zaletą jest “wzorzec poznawczy” - to cecha nie tyle ważna dla kompilatora czy projektu, co dla programisty. Wybór działania na podstawie warunku może być elegancko przedstawiony w wyrażeniu switch, gałęzie są dobrze uwidocznione w strukturze kodu, a czytelnik takiego fragmentu nie musi “skakać” między gałęziami if-elsów bądź operatora ?:.
W javie 23 mamy możliwość (preview) użycia typów podstawowych we wzorcach:
|
|
Niestety, nie są jeszcze wspierane stałe we wzorcach rekordów:
|
|
Tutaj Rust błyszczy jasno na niebie:
|
|
SequencedCollection
W Javie 21 pojaiwł się nowy interfejs SequencedCollection i podinterfejsy SequencedSet i Sequenced Map.
Elementy w kolekcji mają dobrze zdefiniowany porządek (encounter order). Nowe metody w tym interfejsie:
addFirst()addLast()getFirst()getLast()reversed().
Jest on implementowany przez całkiem sporo kolekcji:
AbstractList, AbstractSequentialList, ArrayDeque, ArrayList, AttributeList, ConcurrentLinkedDeque, ConcurrentSkipListSet, CopyOnWriteArrayList, LinkedBlockingDeque, LinkedHashSet, LinkedList, RoleList, RoleUnresolvedList, Stack, TreeSet, Vector,
Źródła
Garść odnośników
Podstawowym źródłem wiedzy o tym, w jaki sposób zmienił się język Java, jest strona openjdk z odnośnikami do JEP-ów w kolejnych wersjach (patrz “Wersja po wersji” poniżej). Kolejnym są notatki do wydania javy 23 na stronie Oracle, wśród których znaleźć można m.in.
- Java API specification (na razie nie wygląda to na wersję do końca oficjalną)
- różnice w API względem Javy 22
- Aneks do specyfikacji języka
Żródłem, które odkryłam stosunkowo niedawno, a które z pewnoscią jest znacznie bardziej lekkostrawne niż suchy język specyfikacji, jest https://foojay.io/, a w nim:
Wersja po wersji
Poniżej lista odnośników do wszystkich JEP-ów:
- Primitive Types in Patterns, instanceof, and switch (Preview)
- Class-File API (Second Preview)
- Markdown Documentation Comments
- Vector API (Eighth Incubator)
- Stream Gatherers (Second Preview)
- Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal
- ZGC: Generational Mode by Default
- Module Import Declarations (Preview)
- Implicitly Declared Classes and Instance Main Methods (Third Preview)
- Structured Concurrency (Third Preview)
- Scoped Values (Third Preview)
- Flexible Constructor Bodies (Second Preview)
- Region Pinning for G1
- Statements before super(…) (Preview)
- Foreign Function & Memory API
- Unnamed Variables & Patterns
- Class-File API (Preview)
- Launch Multi-File Source-Code Programs
- String Templates (Second Preview)
- Vector API (Seventh Incubator)
- Stream Gatherers (Preview)
- Structured Concurrency (Second Preview)
- Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Scoped Values (Second Preview)
- String Templates (Preview)
- Sequenced Collections
- Generational ZGC
- Record Patterns
- Pattern Matching for switch
- Foreign Function & Memory API (Third Preview)
- Unnamed Patterns and Variables (Preview)
- Virtual Threads
- Unnamed Classes and Instance Main Methods (Preview)
- Scoped Values (Preview)
- Vector API (Sixth Incubator)
- Deprecate the Windows 32-bit x86 Port for Removal
- Prepare to Disallow the Dynamic Loading of Agents
- Key Encapsulation Mechanism API
- Structured Concurrency (Preview)
- UTF-8 by Default
- Simple Web Server
- Code Snippets in Java API Documentation
- Reimplement Core Reflection with Method Handles
- Vector API (Third Incubator)
- Internet-Address Resolution SPI
- Foreign Function & Memory API (Second Incubator)
- Pattern Matching for switch (Second Preview)
- Deprecate Finalization for Removal
Zakończenie
Na zakończenie mały bonus: zachęcam do obejrzenia The best of Java Shorts Show - przegląd małych programików, klas, trików, jakie są dostępne programistom bez konieczności instalowania frameworków. To jak powiew świeżego powietrza i przypomnienie, jak dobrze można się bawić mając do dyspozycji jedynie bibliotekę standardową Javy.
Ten wpis jest częścią serii java...
- 2024-01-11 - Java 23 w praktyce
- 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