Java 14 – Co nowego w kolejnym wydaniu?

Java 14 jest już za rogiem. Według oficjalnego planu powinna trafić do nas 17 marca 2020 roku, a wraz z nią szereg nowości. Co zatem znajdziemy w 14 wersji naszego ulubionego języka programowania? 🙂

Wszystkie funkcjonalności opisane są jako JEP – Java Enhancement Proposal. Lista wszystkich JEPów znajduje się poniżej wraz z linkami do krótkiego opisu. W opisie znajduje się też odnośnik do oryginalnej dokumentacji na stronie OpenJDK.

Lista nowości

Preview, Incubator, Standard – co to oznacza?

Niektóre z wymienionych wyżej funkcjonalności mają jeszcze określoną fazę. Po nazwie w nawiasie możesz znaleźć słówka takie jak Preview, Second Preview, Standard, Incubation. Co one właściwie oznaczają?

  • Incubation to pierwszy raz wypuszczony nowy feature, który ma sprawdzić, jak się zachowa w zetknięciu z prawdziwym środowiskiem. Może być jeszcze nie ukończony, nie działać stabilnie, a jego API może ulec zmianie w kolejnej wersji. Możliwe, że jeśli moduł się nie przyjmie, to zostanie usunięty w następnym wydaniu,
  • Preview to funkcjonalność w pełni gotowa, całkowicie zaimplementowana. Jednak może ona ulec jeszcze zmianie w kolejnych wersjach, na podstawie informacji zwrotnej od użytkowników. Funkcjonalności tej można użyć tylko jeśli włączymy flagę –enable-preview przy kompilacji i przy uruchomieniu. W innym wypadku otrzymamy błąd,
  • Second Preview – kolejne preview, plus poprawki na podstawie informacji zwrotnej od użytkowników. Poprawki niemusza być kompatybilne wstecz,
  • Standard – funkcjonalność weszła już do JVMa na stałe.

305: Pattern Matching for instanceof (Preview)

Używając instanceof, do sprawdzenia, czy zmienna jest określonego typu, prawie zawsze kolejną operacją jest przypisanie rzutowanego obiektu do nowej zmiennej. Przykładowo jak poniżej:

if (obj instanceof String) {
String s = (String) obj;
System.out.println(s);
}
view raw PatternMatching.java hosted with ❤ by GitHub

W tym momencie będzie można wpisać nazwę zmiennej od razu po sprawdzanym typie. Dzięki temu kod będzie bardziej zwięzły. Poniżej przykład takiego rozwiązania:

if (obj instanceof String s) {
System.out.println(s);
}

Możemy to też wykorzystać przy definiowaniu warunku w ifach, dla przykładu, jeżeli chcemy sprawdzić, czy zmienna jest ciągiem znaków, który nie jest krótszy niż 5 elementów, to możemy to zrobić tak jak w poniższym kodzie.

if (obj instanceof String s && s.length() > 5) {
return s.contains("Yes!");
}

W przyszłości planowane jest dodanie podobnej możliwości do switchy. Będzie można napisać na przykład coś w tym rodzaju:

String formatted =
switch (obj) {
case Integer i -> String.format("int %d", i);
case Byte b -> String.format("byte %d", b);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s, s);
default -> String.format("Object %s", obj);
};

Oficjalna dokumentacja JEP-305.

343: Packaging Tool (Incubator)

Stworzenie prostego narzędzia, którym zbudujemy natywne paczki dla naszego systemu operacyjnego. Będzie to odpowiednio msi/exe dla Windowsa, pkg i dmg dla MacOS oraz deb i rpm dla Linuksa. Narzędzie bazuje na JavaFX javapackager. Co możemy osiągnąć za pomocą tego narzędzia:

  • Natywny format paczki,
  • Ustawić parametry uruchomienia (linę komend),
  • Odpalić go z linii komend lub programowo przy użyciu ToolProvider API

Oficjalna dokumentacja JEP-343.

345: NUMA-Aware Memory Allocation for G1

NUMA – non-uniform memory access lub niejednolity dostęp do pamięci. W architekturze tej komputer posiada co najmniej dwa procesory. Każdy z procesorów zarządza częścią pamięci. Pomimo że użytkownik widzi spójną logicznie przestrzeń adresową, to czas dostępu do pamięci będzie się różnił, w zależności czy daną część pamięci kontroluje procesor wykonujący instrukcję, czy jakiś inny procesor. Celem tego JEPa jest takie zarządzanie pamięcią, aby procesory wykonujące instrukcje alokowały dostępną pamięć w swoich regionach. ParallelGC ma wsparcie do tego od wielu lat i poprawia to działanie aplikacji uruchamianej na wielu procesorach. Na razie ta funkcjonalność planowana jest tylko dla maszyn działających pod kontrolą Linuksa.

Oficjalna dokumentacja JEP-345.

349: JFR Event Streaming

Jeśli nigdy nie używałeś Java Flight Recording, to w skrócie jest to narzędzie pozwalające nagrywać zdarzenia emitowane przez JVM. Możemy z niego odczytać między innymi: zużycie pamięci i procesora, ilość alokacji sterty, informacje na temat GC (czas trwania, ilość wywołań), itp. Bardzo dużo informacji diagnostycznych, które mogą być użyte do optymalizacji aplikacji. Użytkownik również może emitować swoje zdarzenia, które będą widoczne w nagraniu. JFR potrafi to robić bardzo małym narzutem, mniejszym niż 1%. Do tej pory należało wykonać takie kilkuminutowe nagranie, pobrać je i otworzyć w Java Mission Controll, aby dokonać profilowania aplikacji. W tym momencie jednak chcielibyśmy, aby aplikacja była na bieżąco monitorowana. Celem tej funkcjonalności jest dodanie możliwości stworzenia strumienia zdarzeń i konsumowania go zarówno w aktualnym procesie JVM jak i poza nim.

Oficjalna dokumentacja JEP-349.

352: Non-Volatile Mapped Byte Buffers

Udoskonalenia dla MappedByteBufferu pozwalające na dostęp do nieulotnej pamięci NVM. Dostęp przez to API ma być wydajny i spójny. Celem tej funkcjonalności jest upewnienie się, że pojedyncze zapisy do buforu są zapisywane w pamięci z minimalnym narzutem. Tak, aby wszystkie zmiany w cachu zostały odzwierciedlone w pliku. Dodatkowo, zachowanie to ma być zaimplementowane w wewnętrznym API zdefiniowanym przez Unsafe, umożliwiając ponowne użycie innym klasom poza MappedByteBuffer. Kolejnym elementem jest umożliwienie śledzenia i zarządzania tak mapowanymi buforami przez istniejące narzędzia JVM.

Oficjalna dokumentacja JEP-352.

358: Helpful NullPointerExceptions

Jeśli mamy wywołanie obiektów w sposób: a.b.c.d i któryś z nich jest nullem, to nie będziemy wiedzieć który obiekt w łańcuchu spowodował wyjątek. W nowym wydaniu dostaniemy wyjątek, który mówi, jaki obiekt spowodował wyrzucenie błędu. Będzie to wyglądać mniej więcej tak:

Exception in thread "main" java.lang.NullPointerException: 
         Cannot read field "c" because "a.b" is null
     at Prog.main(Prog.java:5)

Dzięki temu od razu wiemy, że pole b obiektu a było nullem i tam musimy szukać przyczyny błędu.

Oficjalna dokumentacja JEP-358.

359: Records (Preview)

O klasach rekordów pisałem w oddzielnym poście: Java 14 – Record Classes. W dużym skrócie: będziemy mogli tworzyć klasy przechowujące płytkie, niemutowalne dane. Klasy te będą miały bardzo zwięzłą składnię, automatycznie generowane gettery oraz domyślny konstruktor. Przykład możecie znaleźć poniżej.

public record Person(
String firstName,
String lastName,
int age) {}
view raw Person.java hosted with ❤ by GitHub

Więcej przykładów możecie znaleźć we wspomnianym poście. A oficjalna dokumentacja znajduje się tutaj: JEP-359.

361: Switch Expressions (Standard)

Nowa składnia switchy znana jest już od wersji 12. Znajdowała się tam jako preview. W wersji 13 pojawiły się kolejne poprawki bazujące na informacjach zwrotnych od deweloperów i zostało to oznaczone jako second preview. W 14 wchodzi jako standardowa funkcjonalność. Więcej o tym możecie przeczytać w oddzielnym poście: Switch expressions w Java 13 – nowa składnia switchy lub na oficjalnej stronie dokumentacji: JEP-361. Poniżej szybkie porównanie jak wygląda switch w starej wersji i nowej:

public class SwitchExpressions {
public static void main(String[] args) {
DaysOfWeek day = SUNDAY;
System.out.println("Is it a weekend?");
// #1 old way
switch(day) {
case SUNDAY:
case SATURDAY:
System.out.println("Yes!");
break;
case FRIDAY:
System.out.println("Almost!");
break;
case MONDAY:
case TUESDAY:
System.out.println("No");
default:
System.out.println(", but it is closer and closer");
}
// #2 new way
switch (day) {
case SUNDAY, SATURDAY -> System.out.println("Yes!");
case FRIDAY -> System.out.println("Almost!");
case MONDAY, TUESDAY -> System.out.println("No");
default -> System.out.println("No, but it is closer and closer");
}
}
}

362: Deprecate the Solaris and SPARC Ports

Porty na platformy Solaris/SPARC, Solaris/x64 oraz Linux/SPARC zostaną oznaczone jako deprecated. W przyszłych releasach zostaną usunięte całkowicie.

Oficjalna dokumentacja JEP-362.

363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector

Ponad dwa lata temu CMS został oznaczony jako deprecated. W tym czasie zostały wprowadzone dwa nowe GC: Shenandoah i ZGC. Zostało też wprowadzone wiele usprawnień do kolektora G1, który ma być następcą CMSa. Autorzy uznali, że jest już najwyższy czas na pozbycie się CMSa. Próba jego użycia przez opcję -XX:+UseConcMarkSweepGC wygeneruje ostrzeżenia, a JVM użyje domyślnego GC.

Oficjalna dokumentcja: JEP-363

364 i 365: ZGC on macOS and Windows

ZGC to nowy garbage collector, którego celem jest zmniejszenie długości pauz niezależnie od wielkości sterty. Pierwszy raz pojawił się w Javie 11. Jednak wspierany był tylko pod Linuksem. W Javie 14 dostanie wsparcie dla Windowsa i MacOSa.

Oficjalna dokumentacja zmian w JDK: MacOS: JEP-364, Windows: JEP-365. Więcej informacji znajdziesz w Dokumentacji ZGC.

366: Deprecate PareallelScavenge + SerialOld GC Combination

Gdy mamy dostępne nowe generacje garbage collectorów, utrzymywanie starych i mniej wydajnych jest tylko niepotrzebnym obciążeniem. Autorzy postanowili oznaczyć stare GC jako deprecated i w przyszłości usunąć je z kolejnych wydań JDK.

Oficjalna dokumentacja JEP-366.

367: Remove the Pack200 Tools and API

Pack200 używany był do kompresji archiwów jar. Był on stworzony w czasie gdy królowały modemy 56k. W tym momencie przy szybkich łączach już nie ma takiej potrzeby kompresji. Dodatkowo pack200 jest bardzo związany z formatem klasy i wszelkie zmiany w formacie wymagają zmian w algorytmie, przez co zwiększa się narzut czasowy na rozwój. Java 8 jest ostatnią z wersji, która używa jeszcze pack200, od Javy 9 używane są inne narzędzia kompresujące.

Oficjalna dokumentacja JEP-367

368: Text Blocks (Second Preview)

Text Block jest to kolejne wydanie funkcjonalności znanej z Javy 13. Poświęciłem jej cały post: Text Blocks w Java 13. Od poprzedniej wersji zmieniło się tylko to, że dodano możliwość escapowania nowej linii, jeśli na końcu linii wstawimy \ w wynikowym stringu nie zostanie wstawiony znak nowej linii. A jeżeli dodamy \s, zamiast nowej linii zostanie wstawiony znak spacji. Przykład z dokumentacji:

String text = """
Lorem ipsum dolor sit amet, consectetur adipiscing \
elit, sed do eiusmod tempor incididunt ut labore \
et dolore magna aliqua.\
""";
String colors = """
red \s
green\s
blue \s
""";
view raw TextBlocks.java hosted with ❤ by GitHub

Oficjalna dokumentacja JEP-368.

370: Foreign-Memory Access API (Incubator)

Nowe API, które umożliwi dostęp do pamięci poza stertą (Heapem). API to powinno być takie samo do operacji na natywnej pamięci, persystentnej pamięci i zarządzanej pamięci w heapie. Jej użycie powinno być bezpieczne dla JVMa, bez znaczenia jakiej pamięci to dotyczy. Aktualne rozwiązania potrafią wywołać niekontrolowane zamknięcie procesu, na przykład poprzez próbę dostępu do zwolnionej wcześniej pamięci. Dodatkowo powinno być deterministyczne, zwalnianie pamięci będzie musiało być wyrażone w kodzie. To api powinno być alternatywą dla Direct Byte Bufferów oraz dla Unsafe. Przykład użycia: alokacja 100 bajtów w pamięci i ustawienia ich na kolejne liczby od 1 do 25 (integer ma 4 bajty więc zostanie wypełnione całe miejsce).

VarHandle intHandle = MemoryHandles.varHandle(int.class,
ByteOrder.nativeOrder());
try (MemorySegment segment = MemorySegment.allocateNative(100)) {
MemoryAddress base = segment.baseAddress();
for (int i = 0; i < 25; i++) {
intHandle.set(base.addOffset(i * 4), i);
}
}
view raw ForeignMemory.java hosted with ❤ by GitHub

O tym API pojawi się oddzielny wpis na blogu. Tymczasem zapraszam do zapoznania się z oficjalną dokumentacją JEP-370.

Podsumowanie

To już koniec nowości w Javie 14. Jest tu dużo funkcjonalności, na które programiści czekali. Bardzo fajnie wyglądają klasy record, które pozwolą na szybsze tworzenie kodu bez zbędnego boilerplate. Foreign-Memory Access API też wygląda obiecująco, na pewno pozwoli przyśpieszyć wiele aplikacji i zoptymalizować zużycie pamięci, oraz skutecznie zmniejszyć pauzy na GC. Czekam z niecierpliwością na ostateczną wersję.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *