JavaRush /Blog Java /Random-PL /Od 8 do 13: pełny przegląd wersji Java. Część 2

Od 8 do 13: pełny przegląd wersji Java. Część 2

Opublikowano w grupie Random-PL
Artykuł ten stanowi drugą część mojego przeglądu innowacji w Javie w wersjach 8-13. Pierwsza część jest tutaj . Bez zbędnych ceregieli przejdźmy dalej: do 25 września 2018, kiedy wydano nowy JDK:

Java 11

Od 8 do 13: pełny przegląd wersji Java.  Część 2 - 1

var (w lambdzie)

Od teraz możemy określić typy parametrów lambda lub pominąć je przy pisaniu wyrażenia lambda (wpisane domyślnie wyrażenia lambda):
Function<String, String> append = (var string) -> string + " Text";
String appendedString = append.apply("Some");
System.out.println(appendedString);
Możesz także dodawać adnotacje do parametrów lambda bez konieczności wpisywania pełnej nazwy typu zmiennej:
Function<String, String> append = (@NonNull var string) -> string + " Text";

Z(ZGC)

ZGC to nowy moduł zbierający śmieci, który nie działa. Przydziela nową pamięć, ale nigdy jej nie uruchamia ponownie. ZGC obiecuje zarządzać dużymi ilościami pamięci przy dużej przepustowości i małych opóźnieniach (ZGC jest dostępny tylko na platformach 64-bitowych). Kolorowanie referencyjne — ZGC używa wskaźników 64-bitowych z techniką zwaną kolorowaniem wskaźników. Kolorowe wskaźniki przechowują dodatkowe informacje o obiektach na stercie. Kiedy pamięć ulega fragmentacji, pomaga to uniknąć pogorszenia wydajności, gdy GC musi znaleźć miejsce na nową alokację. Zbiórka śmieci za pomocą ZGC składa się z następujących kroków:
  1. przystanki świata: szukamy punktów początkowych dotarcia do obiektów na stercie (takich jak zmienne lokalne lub pola statyczne);
  2. przecięcie grafów obiektów zaczynając od łączy głównych. Zaznaczamy każdy obiekt, do którego dotrzemy (ZGC przegląda wykres obiektu i przygląda się kolorowym wskazówkom, zaznaczając dostępne obiekty);
  3. obsługa niektórych przypadków brzegowych, takich jak słabe łącza;
  4. przesuwanie żywych obiektów, uwalnianie dużych obszarów sterty w celu przyspieszenia alokacji.
  5. kiedy rozpoczyna się faza ruchu, ZGC dzieli stertę na strony i pracuje po jednej stronie na raz;
  6. ZGC kończy ruch wszelkich korzeni i następuje reszta ruchu.
Temat ten jest bardzo złożony i zawiły. Szczegółowe omówienie wymagałoby osobnego artykułu, więc go tu zostawię:

Epsilon GC

Epsilon to moduł zbierający elementy bezużyteczne, który obsługuje alokację pamięci, ale nie implementuje żadnego prawdziwego mechanizmu odzyskiwania pamięci. Po wyczerpaniu dostępnej sterty Java maszyna JVM zostanie zamknięta. Oznacza to, że jeśli zaczniesz tworzyć obiekt w nieskończonej tablicy bez powiązania z referencją za pomocą tego modułu zbierającego elementy bezużyteczne, aplikacja ulegnie awarii z powodu błędu OutOfMemoryError (a jeśli z jakimkolwiek innym, nie nastąpi, ponieważ wyczyści obiekty bez referencji) . Dlaczego jest to potrzebne? Dlatego:
  1. Test wydajności.
  2. Testowanie ciśnienia pamięci.
  3. Testowanie interfejsu maszyny wirtualnej.
  4. Wyjątkowo krótka praca.
  5. Ulepszenia opóźnień ostatniej kropli.
  6. Ulepszenia przepustowości ostatniej kropli.
Przydatne linki: Inne innowacje:
  1. ByteArrayOutputStreammam metodę void writeBytes(byte []), która zapisuje wszystkie bajty z argumentu do OutputStream.
  2. FileReaderi FileWriterotrzymałem nowe konstruktory, które pozwalają określić Charset.
  3. Pathpobrał dwie nowe metody, of(String, String [])zwraca Pathz argumentu typu string ścieżkę lub sekwencję ciągów, które po połączeniu tworzą ciąg ścieżki, a of(URI): zwraca ścieżkę z identyfikatora URI.
  4. Pattern— otrzymano metodę asMatchPredicate()sprawdzającą, czy dany ciąg wejściowy pasuje do danego wzorca (czy pozwala na utworzenie predykatu za pomocą wyrażenia regularnego, dzięki czemu można np. filtrować dane w strumieniu).
  5. StringWybrałem wiele przydatnych metod, takich jak:
    • String strip(): zwróci nam ciąg będący tym ciągiem, z usuniętymi wszystkimi spacjami na początku i na końcu ciągu (podobnie jak trim(), ale spacje definiuje inaczej);
    • String stripLeading(): zwróci nam ciąg znaków, który jest tym ciągiem, usuwając wszelkie początkowe spacje z ciągu;
    • String stripTrailing(): zwróci nam ciąg znaków, który jest tym ciągiem, usuwając spacje na końcu ciągu;
    • Stream lines(): zwróci nam Streamz Stringwyodrębnionego z tego ciągu znaków, oddzielonego separatorami linii;
    • String repeat(int): zwróci nam ciąg będący konkatenacją tego ciągu, powtórzoną określoną liczbę razy.
    • boolean isBlank(): zwróci wartość true, jeśli ciąg znaków jest pusty lub zawiera tylko spacje, w przeciwnym razie wartość false.
  6. Thread— metodyzniszcz() i stop(Throwable) zostały usunięte.
  7. Filesmam wiele nowych metod:
    • String readString(Path): wczytuje wszystkie dane z pliku do ciągu znaków, dekodując bajty na znaki przy użyciu kodowania UTF-8;
    • String readString(Path, Charset): tak samo jak w metodzie powyżej, z tą różnicą, że dekodowanie bajtów na znaki odbywa się przy użyciu określonego zestawu znaków;
    • Path writeString (Path, CharSequence, OpenOption []): Zapisuje ciąg znaków do pliku. Znaki są kodowane w bajtach przy użyciu kodowania UTF-8;
    • Path writeString(Path, CharSequence,Charset, OpenOption []): Ta sama metoda co powyżej, tylko znaki są kodowane w bajtach przy użyciu kodowania określonego w Charset.
To były najciekawsze innowacje API (moim skromnym zdaniem), oto kilka materiałów do bardziej szczegółowej recenzji:

Java 12

Mija sześć miesięcy i widzimy kolejny etap ewolucji Javy. Czas więc wyjąć łopatę wiedzy i kopać. Od 8 do 13: pełny przegląd wersji Java.  Część 2 - 2

Zaktualizuj G1

W G1 wprowadzono następujące ulepszenia:
  1. Odzyskaj nieużywaną przydzieloną pamięć

    W pamięci sterty Java istnieje coś takiego jak pamięć nieużywana (lub innymi słowy nieaktywna). W Javie 12 postanowili rozwiązać ten problem, teraz:

    • G1 zwraca pamięć ze sterty w pełnym GC lub podczas pętli równoległej; G1 próbuje zapobiec pełnemu GC i rozpoczyna pętlę równoległą w oparciu o alokację sterty. Będziemy musieli zmusić G1 do zwrócenia pamięci ze sterty.

    To ulepszenie koncentruje się na wydajności poprzez automatyczne zwracanie pamięci ze sterty do systemu operacyjnego, gdy G1 nie jest używany.

  2. Przerywanie mieszanych kolekcji po przekroczeniu czasu pauzy

    G1 korzysta z silnika analitycznego, aby wybrać ilość pracy wymaganą do usunięcia elementów bezużytecznych. Zbiera żywe obiekty bez zatrzymywania się po zdefiniowaniu zestawu i rozpoczęciu czyszczenia. Powoduje to, że moduł zbierający elementy bezużyteczne przekracza docelowy czas pauzy. W rzeczywistości problem ten został rozwiązany poprzez ulepszenie, ponieważ jeśli czas wykonania następnego kroku przekracza rozsądne granice, etap ten może zostać przerwany.

Mikrobenchmark

W Javie 12 wprowadzono testy mikrobenchmarkingu, dzięki czemu wydajność JVM można łatwo przetestować przy użyciu istniejących testów porównawczych. Byłoby to bardzo przydatne dla każdego, kto chce pracować nad samą maszyną JVM. Dodane testy są tworzone przy użyciu Java Microbenchmark Harness (JMH). Testy te pozwalają na ciągłe testowanie wydajności na maszynie JVM. JEP 230 proponuje wprowadzenie około 100 testów, a nowe testy będą wprowadzane w miarę wydawania nowych wersji Java. Oto przykład dodanych testów .

Shenandoah

Jest to algorytm zbierania śmieci (GC), którego celem jest zagwarantowanie krótkiego czasu odpowiedzi (dolny limit to 10-500 ms). Skraca to czas pauzy GC podczas wykonywania prac porządkowych jednocześnie z uruchomionymi wątkami Java. W Shenandoah czas pauzy jest niezależny od wielkości sterty. Oznacza to, że czas pauzy będzie taki sam niezależnie od wielkości sterty. Jest to funkcja eksperymentalna i nie jest zawarta w standardowej (Oracle) wersji OpenJDK.

Ulepsz przełącznik

W Javie 12 udoskonalono wyrażenia Switch do dopasowywania wzorców. Wprowadzono nową składnię L →. Oto lista kluczowych punktów nowego przełącznika :
  1. Nowa składnia eliminuje potrzebę stosowania instrukcji break, aby zapobiec błędom.
  2. Wyrażenia przełączające nie zawodzą już.
  3. Dodatkowo możemy zdefiniować wiele stałych w jednej etykiecie.
  4. Domyślna wielkość liter jest teraz wymagana w wyrażeniach przełączających.
  5. break służy w wyrażeniach Switch do zwracania wartości z samego rejestru (w rzeczywistości przełącznik może zwracać wartości).
Spójrzmy na to jako przykład:
var result = switch (someDay) {
  case "M", "W", "F" -> "MWF";
  case "T", "TH", "S" -> "TTS";
  default -> {
      if(someDay.isEmpty())
            break "Please insert a valid day.";
      else
            break "Looks like a Sunday.";
  }
};
Ostateczny przewodnik po przełączaniu wyrażeń w Javie 13 Inne nowe funkcje:
  1. String:

    transform(Function f)- Stosuje podaną funkcję do ciągu znaków. Wynikiem może nie być ciąg znaków.
    indent(int x)— dodaje x spacji do ciągu. Jeśli parametr jest ujemny, to ta liczba wiodących spacji zostanie usunięta (jeśli to możliwe).

  2. Files- złapał metodę taką jak mismatch(), która z kolei znajduje i zwraca pozycję pierwszego niedopasowanego bajtu w zawartości dwóch plików lub -1L, jeśli nie ma niezgodności.

  3. Pojawiła się nowa klasa -CompactNumberFormat do formatowania liczby dziesiętnej w formie zwartej. Przykładem tej zwartej formy jest 1M zamiast 1 000 000. Zatem wymagane są tylko dwa dwa zamiast dziewięciu znaków.

  4. Jest też nowy enum , NumberFormatStylektóry ma dwie wartości – LONG i SHORT.

  5. InputStream mam metodę skipNBytes(long n) : pomiń n-tą liczbę bajtów ze strumienia wejściowego.

Ciekawe linki Java 12:

Jawa 13

Świat nie stoi w miejscu, porusza się, rozwija, tak jak Java - Java 13. Od 8 do 13: pełny przegląd wersji Java.  Część 2 - 3

Blok tekstowy

Java zawsze trochę cierpiała, jeśli chodzi o definiowanie ciągów znaków. Jeśli musieliśmy zdefiniować linię ze spacją, podziałem linii, cudzysłowem lub czymś innym, powodowało to pewne trudności, więc musieliśmy użyć znaków specjalnych: na przykład \n dla podziału linii lub ucieczki z części linii samo. To znacznie zmniejsza czytelność kodu i zabiera dodatkowy czas przy pisaniu takiej linii. Staje się to szczególnie zauważalne podczas pisania ciągów znaków wyświetlających JSON, XML, HTML itp. W rezultacie, jeśli będziemy chcieli napisać małego Jsona, będzie on wyglądał mniej więcej tak:
String JSON_STRING = "{\r\n" + "\"name\" : \"someName\",\r\n" + "\"site\" : \"https://www.someSite.com/\"\r\n" + "}";
I wtedy na scenę wchodzi Java 13, która oferuje nam swoje rozwiązanie w postaci potrójnych podwójnych cudzysłowów przed i po tekście (które nazywają blokami tekstowymi). Spójrzmy na poprzedni przykład jsona z wykorzystaniem tej innowacji:
String TEXT_BLOCK_JSON = """
{
    "name" : "someName",
    "site" : "https://www.someSite.com/"
}
""";
O wiele prościej i jaśniej, prawda? Dodano także odpowiednio Stringtrzy nowe metody zarządzania tymi blokami:
  • stripIndent(): Usuwa losowe spacje z ciągu. Jest to przydatne, jeśli czytasz ciągi wielowierszowe i chcesz zastosować ten sam rodzaj losowego wykluczenia białych znaków, który występuje w przypadku jawnej deklaracji (zasadniczo symulując kompilator w celu usunięcia losowych białych znaków);
  • formatted(Object... args ): podobny do format(String format, Object... arg), ale dla bloków tekstowych;
  • translateEscapes(): Zwraca ciąg znaków z sekwencjami specjalnymi (takimi jak \r) przetłumaczonymi na odpowiednią wartość Unicode.

Ulepsz przełącznik

Wyrażenia przełączające zostały wprowadzone w Javie 12, a wersja 13 je udoskonala. W 12 definiujesz zwracane wartości za pomocą break. W 13 wartość zwracaną zastąpiono wydajnością. Teraz wyrażenie przełączające, które mieliśmy w sekcji Java 12, można przepisać jako:
var result = switch (someDay) {
  case "M", "W", "F" -> "MWF";
  case "T", "TH", "S" -> "TTS";
  default -> {
      if(someDay.isEmpty())
          yield "Please insert a valid day.";
      else
          yield "Looks like a Sunday.";
  }
};
Chociaż akceptowanie przerwy przez nas, programistów już zaznajomionych z Javą, było czymś normalnym, było to jednak dość dziwne. Co to jest „łamanie prawdy” próbując mi powiedzieć? Nowe (stosunkowo nowe) słowo kluczowe return jest bardziej przejrzyste i może w przyszłości pojawić się w innych miejscach, w których zwracane są wartości. Osobom mocno zainteresowanym tym tematem polecam zapoznać się z poniższymi materiałami:

Dynamiczne archiwa CDS

CDS – udostępnianie danych klasowych. Umożliwia spakowanie zestawu często używanych klas w archiwum, które może być później załadowane przez wiele instancji JVM. Dlaczego tego potrzebujemy? Faktem jest, że w procesie ładowania klas JVM wykonuje sporo czynności wymagających dużych zasobów, takich jak czytanie klas, przechowywanie ich w strukturach wewnętrznych, sprawdzanie poprawności odczytanych klas, wyszukiwanie i ładowanie klas zależnych itp. ., i dopiero po tym wszystkim klasy są gotowe do pracy. Zrozumiałe jest, że marnuje się dużo zasobów, ponieważ instancje JVM często mogą ładować te same klasy. Na przykład String, LinkedList, Integer. Cóż, albo klasy tej samej aplikacji, a wszystkie z nich są zasobami. Gdybyśmy tylko raz wykonali wszystkie niezbędne kroki, a następnie umieścili przeprojektowane klasy w archiwum, które można było załadować do pamięci kilku maszyn JVM, mogłoby to znacznie zaoszczędzić miejsce w pamięci i skrócić czas uruchamiania aplikacji. Właściwie CDS umożliwia utworzenie właśnie takiego archiwum. Java 9 pozwalała na dodawanie do archiwum tylko klas systemowych. Java 10 — dołącz klasy aplikacji do archiwum. Utworzenie takiego archiwum polega na:
  • utworzenie listy klas ładowanych przez aplikację;
  • tworzenie bardzo potrzebnego archiwum z klasami, które znaleźliśmy.
Innowacja w Javie 13 ulepsza CDS, dzięki czemu może utworzyć archiwum po zakończeniu działania aplikacji. Oznacza to, że dwa powyższe kroki zostaną teraz połączone w jeden. I jeszcze jedna ważna uwaga: do archiwum zostaną dodane tylko klasy, które zostały załadowane podczas działania aplikacji. Innymi słowy, te klasy, które nadal znajdują się w pliku application.jar, ale z jakiegoś powodu nie zostały załadowane, nie zostaną dodane do archiwum.

Zaktualizuj interfejs API gniazda

Interfejs API gniazd ( java.net.Socket i java.net.ServerSocket ) jest zasadniczo integralną częścią języka Java od jego powstania, ale gniazda nigdy nie były aktualizowane w ciągu ostatnich dwudziestu lat. Napisane w C i Javie, były bardzo, bardzo nieporęczne i trudne w utrzymaniu. Ale Java 13 zdecydowała się wprowadzić własne poprawki w tej całej sprawie i zastąpiła podstawową implementację. Teraz zamiast PlainSocketImpl interfejs dostawcy został zastąpiony przez NioSocketImpl . Ta nowa, kodowana implementacja opiera się na tej samej infrastrukturze zaplecza, co java.nio . Zasadniczo klasa wykorzystuje pamięć podręczną bufora java.util.concurrent i mechanizm blokujący (oparty na segmentach), a nie metody zsynchronizowane. Nie wymaga już kodu natywnego, co ułatwia przenoszenie na różne platformy. Nadal mamy sposób na powrót do używania PlainSocketImpl , ale od tej pory domyślnie używany jest NioSocketImpl .

Powrót pamięci dla ZGC

Jak pamiętamy, moduł zbierający elementy bezużyteczne Z został wprowadzony w Javie 11 jako mechanizm usuwania elementów bezużytecznych o niskim opóźnieniu, dzięki czemu pauza GC nigdy nie przekracza 10 ms. Ale jednocześnie, w przeciwieństwie do innych wirtualnych HotSpotów GC, takich jak Shenandoah i G1, może zwrócić nieużywaną pamięć dynamiczną do systemu operacyjnego. Ta modyfikacja dodaje tę możliwość J do ZGC. W związku z tym uzyskujemy zmniejszone zużycie pamięci wraz z lepszą wydajnością, a ZGC teraz domyślnie zwraca niezatwierdzoną pamięć do systemu operacyjnego, aż do osiągnięcia określonego minimalnego rozmiaru sterty. Jeszcze jedno: ZGC ma teraz maksymalny obsługiwany rozmiar sterty wynoszący 16 TB. Wcześniej limitem było 4 TB. Inne innowacje:
  1. javax.security- dodano opcję jdk.sasl.disabledMechanismswyłączającą mechanizmy SASL.
  2. java.nio- dodano metodę FileSystems.newFileSystem (Path, Map <String,?>)- odpowiednio utworzenia nowego pliku.
  3. Klasy java.niomają teraz metody bezwzględne (w przeciwieństwie do względnych) geti set-. Zawierają one, podobnie jak podstawowa klasa abstrakcyjna Buffer, metodę slice()pobierania części bufora.
  4. Dodano javax.xml.parsersmetody tworzenia instancji fabryk DOM i SAX (z obsługą przestrzeni nazw).
  5. Obsługa Unicode została zaktualizowana do wersji 12.1.
Ciekawe linki na temat Java 13:

Wyniki

Moglibyśmy jeszcze omówić zapowiadane innowacje w Javie 14, ale skoro ujrzy ona światło dzienne dość szybko – premiera JDK 14 przewidziana jest na 17 marca 2020 r., najlepiej byłoby przeprowadzić od razu po jej wydaniu oddzielną, pełną recenzję . Chciałbym również zwrócić uwagę na fakt, że w innych językach programowania z długimi przerwami między wydaniami, jak np. Python 2–3, nie ma kompatybilności: to znaczy, jeśli kod jest napisany w Pythonie 2, muszę ciężko pracować, tłumacząc to na wersję 3. Java jest pod tym względem wyjątkowa, ponieważ jest wyjątkowo kompatybilna wstecz. Oznacza to, że Twój program Java 5 lub 8 będzie działał na maszynie wirtualnej Java 8–13 — z kilkoma wyjątkami, którymi na razie nie musisz się martwić. Oczywiste jest, że nie działa to w drugą stronę: na przykład, jeśli Twoja aplikacja korzysta z funkcji Java 13, które po prostu nie są dostępne w JVM Java 8. To wszystko, co mam na dzisiaj, szacunek dla tych, którzy przeczytali do tego momentu)) Od 8 do 13: pełny przegląd wersji Java.  Część 2 - 5
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION