Dzisiaj temat mógł być tylko jeden – premiera JDK 19! Dlatego też poświęciłem jej całą edycję, przechodząc przez poszczególne JEPy składające się na to wydanie.
No i mamy to! Zgodnie z zaplanowanym harmonogramem, ukazało się JDK 19. Wydanie to z jednej strony wydawać się może czymś małym, jednak niech nie zmylą Was pozory jedynie pojedynczej stabilnej funkcjonalności – mamy bowiem do czynienia z jednym z najważniejszych nowych JDK od lat, skłonny jestem stwierdzić, że nawet od czasu JDK 9 z jego systemem modułów. Po raz pierwszy bowiem mamy okazję wersje Preview projektów, które stanowić będą przyszłość JVM.
Zanim przejdę do własnego podsumowania poszczególnych JEPów, które trafiły do tego wydania – jeżeli chcecie zobaczyć oficjalne zapowiedzi, Oracle przygotowało aż trzy. Do wyboru macie:
- release note od Oracle, podsumowujący ilość zmian i osoby zaangażowane w stworzenie JDK 19
- bardziej biznesowo-korporacyjną zapowiedź od Oracle
- podcast, którego gośćmi są Ron Pressler oraz Brian Goetz
To jak oficjalną część mamy za sobą, teraz parę groszy ode mnie. Postanowiłem przejść przez poszczególne JEP-y i przy każdym podzielić się krótką refleksją.
422: Linux/RISC-V Port
No to zacznijmy od jedynej stabilnej zmiany w JDK 19 – otóż Java trafia na nową platformę. Tym razem jest to Linux, ale nie taki zwykły Linux. Twórcy Javy pokusili się bowiem o wsparcie dystrybucji uruchamianych na procesorach z rodziny RISC-V.
RISC-V jest stworzonym przez amerykanów z Uniwersytetu w Berkley otwartym standardem, będącym swego rodzaju alternatywą dla ARM. RISC-V nie jest gotowym procesorem, a raczej architektura zestawu instrukcji (z angielskiego ISA), starający się dostarczyć ściśle wyspecjalizowanego zestawu takowych – reduced instruction set computer – RISC właśnie. Cytując Wikipedię:
W kontraście do większości ISA, RISC-V może być swobodnie używany w dowolnym celu, umożliwiając każdemu projektowanie, produkcję i sprzedaż czipów i oprogramowania RISC-V. Chociaż nie jest pierwszą otwartą architekturą ISA ma duże znaczenie, ponieważ został zaprojektowany z myślą o nowoczesnych skomputeryzowanych urządzeniach, takich jak ogromne chmury obliczeniowe, wysokiej klasy telefony komórkowe i najmniejsze systemy wbudowane.
I dlatego też właśnie robi się o tej architekturze ostatnio głośno. Bo o ile w sama sobie nie jest chińska to faktem jest, że to rzeczywiście właśnie Chińczycy zaczęli w nią mocno inwestować. Oprócz swoich niewątpliwych zalet od strony technicznej (programistów RISC-V szuka obecnie min. Apple), architektura w wyniku ostatnich zawirowań politycznych. Jako standard realnie otwarty jawi się bowiem jako swoista bezpieczna przystań dla wszystkich, którzy nie chcą być uzależnieni od widzimisie ARM i amerykańskiej strefy wpływów. Stąd też zainteresowanie ze strony Chin, Rosji czy też… Unii Europejskiej, która to w zeszłym roku ogłosiła stworzenie opartego o RISC-V chipa EPAC (European Processor Accelerator), który ma być kamieniem milowym jeśli chodzi o uzyskanie przez UE pozycji na rynku producentów procesorów. W ręce wpadł mi też kiedyś raport opublikowany przez firmę Conunterpoint, że do 2025 roku architektura RISC-V może napędzać 25% projektów związanych z Internetem Rzeczy.
Sam z zainteresowaniem obserwuje RISC-V i mam nadzieje, że spełni ona pokładane w niej nadzieje. Jeśli chodzi o rynek procesorów, nie ma chyba bardziej gorącego tematu (no, może poza kolejnymi iteracjami M1/M2).
Jedyny stabilny dodatek do JDK mamy za sobą, czas zstąpić do piekieł featurów preview.
Zainstaluj teraz i czytaj tylko dobre teksty!
425: Virtual Threads (Preview)
Zacznijmy od informacji na którą wszyscy czekali (a która nie będzie dla nikogo czytającego te przeglądy niespodzianką) – w JDK 19 zobaczyliśmy wreszcie pierwszy preview oczekiwanego od lat Looma. Społeczność bawi się całością w najlepsze od dłuższego czasu, a teraz również programiści obawiający się wersji rozwojowych będą mogli pobawić się wirtualnymi wątkami i bezboleśnie sprawdzić, czy całość wytrzymała cały hype z jakim wiązały się kolejne zapowiedzi projektu.
Nie będę się tutaj mocno rozpisywał – o eksperymentach społeczność, która bawi się wirtualnymi wirtualnymi wątkami już od pewnego czasu, sprawdzając w praktyce projekt poświęciłem kiedyś sporą część przeglądu, więc zachęcam do odwiedzenia jednej z poprzednich edycji. Znajdziecie tam przegląd eksperymentów, które wypączkowały jeszcze w momencie opublikowania Javy we wczesnym dostępie.
O ile jednak o wirtualnych wątkach powiedziano już naprawdę dużo, o tyle znacznie ciszej jest o kolejnym ważnym, powiązanym z nią featurze:
428: Structured Concurrency (Incubator)
Długo oczekiwana Strukturalna Współbieżność. który właśnie trafił do inkubacji, też jest bowiem częścią Looma i stanowi naturalne uzupełnienie Wirtualnych Wątków…
Czym jest strukturalna współbieżność? Jeśli ktoś nie chce próbować dokopywać się do jakichś zakurzonych papierów z lat 60-tych (bo tam można znaleźć wszystko) jej korzeni należy doszukiwać się poście blogowym Structured Concurrency z 2016 roku, napisanym przez Martina Sústrika – twórcy ZeroMQ. To właśnie w nim zaprezentował on koncepcje enkapsulowania współbieżnych wątków wykonawczych za pomocą bloków kodu o jasnych miejscach startu i zakończenia, które gwarantowałyby, że wszystkie wątki kończą pracę przed wyjściem z danego bloku. Tego typu podejście w znacznym stopniu ułatwia rozumowanie na temat kodu, a również obsługę błędów.
Idea pewnie nigdy nie zdobyłaby aż takiej popularności gdyby nie Roman Elizarov, architekt kotlinowych korutyn, który postanowił wykorzystać ją w praktyce przy projektowaniu mechanizmu. Efekty okazały się być na tyle dobre, że w całym JVM-ie nastąpiła spora zmiana w myśleniu i – przykładowo – oryginalna wersja projektu Loom poszła w zasadzie do kosza, a ostateczny wariant, o którym pisaliśmy dwa tygodnie temu, to już rozwiązanie w pełni ze Strukturalną Współbieżnością kompatybilne.
Jeżeli to, o czym pisałem kojarzy Wam się z wprowadzonym w Javie 1.7 try-with-resources
to macie bardzo dobre skojarzenia. Właśnie na tej znajomej programistom Javy konstrukcji projektanci Looma zdecydowali się oprzeć swoją wersję strukturalnej współbieżności:
Response handle() throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join(); // Join both forks
scope.throwIfFailed(); // ... and propagate errors
// Here, both forks have succeeded, so compose their results
return new Response(user.resultNow(), order.resultNow());
}
}
W powyższym przykładzie blok try automatycznie “posprząta” wszystkie stworzone w nim wątki w wypadku jakiegokolwiek problemu. Jasno sprecyzowany jest też cykl życia całości, wygodnie zbiera się też rezultaty, ponieważ całość zachowuje się w zasadzie jak kod synchroniczny.
W odróżnieniu od samych wirtualnych wątków, opublikownych jako Preview, JEP 428: Structured Concurrency znajduje się w inkubacji – w związku z czym powyższe API może jeszcze ulec ewolucji. To co twórcy chcą teraz osiągnąć, to zdobycie opinii społeczności w celu doprecyzowania docelowe API.
Ja na pewno się pobawię. Mam nadzieje, że będziecie mi towarzyszyć 😉
Dobra, to jak Looma mamy z głowy, przechodzimy dalej – Projekt Panama.
424: Foreign Function & Memory API (Preview)
Kolejny gracz wagi ultraciężkiej, czyli efekt Projektu Panama, również widzimy w nowym wydaniu JDK. Przed nami materializuje się następca JNI, który zapewnić ma nam nową, lepszą integrację z natywnym kodem i pamięcią.
Nowe API jest naprawdę potężne – o możliwościach, które daje piszemy regularnie (choćby w poprzedniej edycji). Temat jest na tyle szeroki, że aby poznać więcej szczegółów, polecam prezentację od Oracle, która pokrywa w pełni JEP-424. Posiada wiele przykładów pozwalających nie tylko lepiej zrozumieć, jak pierwszego dużego dziecka Projektu Panama używać, ale również dlaczego w ogóle warto się nim zainteresować.
426: Vector API (Fourth Incubator)
Coś nie może wyjść z inkubacji to Vector API… To już czwarty raz, kiedy dostajemy jego przebudowę, co tylko udowadnia, za jak skomplikowany temat wzięli się twórcy JVMa. Współczesne procesory zapewniają możliwość równoległego przetwarzania danych, ale miedzy poszczególnymi implementacjami istnieją znaczące różnice. Vector API zapewnić ma specjalną, wspólną warstwę abstrakcji. Jedną z ważnych nowości jest użycie nowości wprowadzonych w dopiero co opisywanym JEP 424, jako, że wreszcie doczekaliśmy się oficjalnego preview.
Jeżeli chcecie dowiedzieć się więcej o Vector API i motywacjach za nim stojących, zamiast lektury JEP-a polecam odcinek podcastu Inside Java, w którym autorzy całości (John Rose i Paul Sandoz) opowiadają o motywacjach stojących za projektem, pozwalając lepiej zrozumieć zarówno dlaczego jest tak istotny, jak i dlaczego jego implementacja jest tak wyboista i długa.
427: Pattern Matching for switch (Third Preview)
Tutaj (podobnie jak w wypadku Vector API) ochy i achy trochę mniejsze, bo to już trzecia iteracja Pattern Matchingu dla javowych switchy. Zmiany wydają się być na plus – całkiem podoba mi się użycie słówka when dla operacji warunkowych (choć przyznam, że będzie mi się nieco gryzło z użyciem Kotlinowym). Czekam na switche bardzo i mam nadzieje, że to jest ostatnie preview i już niedługo doczekamy się wersji stabilnej. A jeśli chcecie więcej i nie lubicie formatu JEPów, polecam kolejne wideo-wprowadzenie od Oracle, prowadzone przez Venkata Subramaniana, częstego (i bardzo popularnego) gościa konferencji.
405: Record Patterns (Preview)
Ostatnim z nowych JEPów jest pierwsza wersja Preview pattern matchingu również dla Rekordów. Ma on pozwolić na łatwą destrukturyzacje struktury i (przynajmniej z mojej perspektywy) stanowić pierwszą prawdziwą realną przewagę tej struktury w stosunku do POJO generowanych przez IDE. Okazuje się, że dzięki ustandaryzowanemu sposobowi w jaki rekordy są tworzone i przechowywane na JVM, twórcy JDK mają otwartą drogę na wprowadzenie nowych funkcjonalności. Pierwszą z nich (i na pewno nie ostatnią – zachęcam lekturę dokumentu Functional Transformation of Immutable Objects, którym kiedyś podzielił się Brian Goetz) jest właśnie wprowadzenie specjalnej składni dla pattern matchingu dedykowanej dla tej struktury.
Jeżeli jesteście ciekawi, jak wygląda składnia, poniżej znajdziecie
record Person (String name, String address) {}
if (obj instanceof Person(var name, var address)) {
println(name)
println(address)
}
Record Patterns umożliwiają również warunkowe castowanie
if (obj instanceof Person p) {
var name = p.name();
var address = p.address();
}
Wewnątrz bloku warunkowego możemy w bezpieczny sposób możemy używać obiektu w taki sposób, jakby ten został poddany castingowi. Podejrzewa, że jeśli mieliście do czynienia z Kotlinem, to ta struktura będzie dla Was znajoma.
Więcej szczegół znajdziecie w JEPie, a jeśli chodzi o potencjalne przypadki użycia, bardzo dobre wprowadzenie znajdziecie w Java Almanach
Zainstaluj teraz i czytaj tylko dobre teksty!
Bonus: Project Lanai jako default
To jednak nie wszystko, czego można się spodziewać po nowym wydaniu. JDK 19 to także przepięcie się Javy na nowy sposób renderowania aplikacji Desktopowych na komputerach z systemem macOS – OpenGL został zastąpiony przez Metal API. Jest to inicjatywa, której efekty trafiły do Javy jeszcze w wersji 17 w ramach projektu Lanai, a od następnej wersji JDK zostały w końcu włączone jako domyślne.
Ufff, sporo tego. A wiecie co najbardziej mnie “jara”? Jest spora szansa, że choć część z powyższych Preview już niedługo stanie się stabilne wraz z następnym LTS (JDK 21). Już nie mogę się doczekać, jakie będą kolejne pomysły tych wszystkich utalentowanych inżynierów, którzy po latach pracy nad Loomem czy Panamą będą mogli zabrać się za coś nowego. Ciekawe jak będzie wyglądało JDK 29.
PS: Wszystkich zapraszam na YavaConf w Warszawie, gdzie będę miał okazje zaprezentować swój nowy talk JVM Iceberg… we need to go deeper. Możecie go potraktować jako live edycje tego Weekly 🤟