JavaRush /Java блог /Random UA /З 8 до 13: повний огляд версій Java. Частина 2
Константин
36 рівень

З 8 до 13: повний огляд версій Java. Частина 2

Стаття з групи Random UA
Ця стаття є другою частиною мого огляду за нововведеннями Java версій 8-13. Перша частина - тут . Без зайвих передмов рухаємося далі: у 25 вересня 2018 року, коли і вийшла нова JDK:

Java 11

З 8 до 13: повний огляд версій Java.  Частина 2 - 1

var (у лямбді)

Відтепер і на віки віків ми можемо вказати типи лямбда-параметрів або пропустити їх при написанні лямбда-вирази (неявно типізованих лямбда-виразів):
Function<String, String> append = (var string) -> string + " Text";
String appendedString = append.apply("Some");
System.out.println(appendedString);
Також можна додавати інструкції до лямбда-параметрів без необхідності писати повне ім'я типу змінної:
Function<String, String> append = (@NonNull var string) -> string + " Text";

Z (ZGC)

ZGC — це новий збирач сміття, яке не працює. Він виділяє нову пам'ять, але ніколи не перезапускає її. ZGC обіцяє керувати великими обсягами пам'яті з високою пропускною здатністю та коротким часом паузи (ZGC доступний лише на 64-бітових платформах). Еталонне забарвлення - ZGC використовує 64-бітові покажчики з технікою, яка називається фарбуванням покажчиків. Кольорові покажчики зберігають додаткову інформацію про об'єкти купи. Коли пам'ять стає фрагментованою, це допомагає уникнути зниження продуктивності, коли GC необхідно знайти місце нового розподілу. Складання сміття за допомогою ZGC складається з таких етапів:
  1. зупинки світу: ми шукаємо відправні точки для досягнення об'єктів у купі (наприклад, локальних змінних чи статичних полів);
  2. перетин граф об'єктів, починаючи з кореневих посилань. Ми відзначаємо кожен об'єкт, який досягаємо (ZGC ходить по графі об'єктів та досліджує кольорові покажчики, позначаючи доступні об'єкти);
  3. обробки деяких крайніх випадків, наприклад слабких посилань;
  4. рух живих об'єктів, звільняючи великі ділянки купи, щоб прискорити розподіл.
  5. коли починається фаза переміщення, ZGC поділяє купу на сторінки і по одній сторінці за раз;
  6. ZGC закінчує рух будь-якого коріння, і відбувається решта переміщення.
Ця тема дуже складна та заплутана. Детальний розгляд тягне на окрему статтю, тож просто залишу це тут:

Epsilon GC

Епсилон - це збирач сміття, який обробляє виділення пам'яті, але не реалізує будь-який реальний механізм відновлення пам'яті. Як тільки доступна купа Java буде вичерпана, JVM закриється. Тобто, якщо в нескінченному масиві запустити створення об'єкта без прив'язки до посилання з даним збирачем сміття, програма впаде з OutOfMemoryError (а якщо з будь-яким іншим немає, тому що він підчищатиме об'єкти без посилань). Навіщо він потрібен? А ось навіщо:
  1. Тестування продуктивності.
  2. Тестування тиску пам'яті.
  3. Тестування інтерфейсу VM.
  4. Надзвичайно недовга робота.
  5. Поліпшення латентності останньої краплі.
  6. Поліпшення пропускної спроможності останньої краплі.
Корисні посилання: Інші нововведення:
  1. ByteArrayOutputStreamотримав метод void writeBytes(byte []), що записує всі байти з аргументу в OutputStream.
  2. FileReaderта FileWriterотримали нові конструктори, що дозволяють вказувати Charset.
  3. Pathвідхопив два нових методи, of(String, String [])що повертає Pathз рядкового аргументу шляху або послідовності рядків, які при об'єднанні утворюють рядок шляху і of(URI): повертає Path з URI.
  4. Pattern— отримав метод asMatchPredicate(), який перевіряє, чи відповідає заданий рядок введення, заданому шаблону (дозволяє створити предикат за регулярним виразом, щоб можна було, наприклад, фільтрувати дані в stream).
  5. Stringвідхопив багато корисних методів, таких як:
    • String strip(): поверне нам рядок, який є цим рядком, при цьому видаляються всі прогалини на початку та в кінці рядка (аналог trim(), але по-іншому визначає прогалини);
    • String stripLeading(): поверне нам рядок, який є цим рядком, при цьому видаляються всі прогалини на початку рядка;
    • String stripTrailing(): поверне нам рядок, який є цим рядком, при цьому видаляються всі прогалини в кінці рядка;
    • Stream lines(): поверне нам Streamз String, витягнутих із цього рядка, поділених роздільниками рядків;
    • String repeat(int): поверне нам рядок, який є конкатенацією цього рядка, повторюється кількість разів.
    • boolean isBlank(): поверне нам true, якщо рядок порожній або містить лише пробіли, інакше false.
  6. Thread- були видалені методи destroy() та stop(Throwable).
  7. Filesотримав низку нових методів:
    • String readString(Path): читає всі дані з файлу в рядок, при цьому декодуючи з байт символи з використанням кодування UTF-8;
    • String readString(Path, Charset): так само, як і в методі вище, з різницею в тому, що декодування з байт символи відбувається з використанням вказаної Charset;
    • Path writeString (Path, CharSequence, OpenOption []): записує послідовність символів у файл. Символи кодуються в байти, використовуючи кодування UTF-8;
    • Path writeString(Path, CharSequence,Charset, OpenOption []): такий самий метод, як і вище, тільки символи кодуються в байти, використовуючи кодування, вказане в Charset.
Це були найцікавіші нововведення API (на мою скромну думку), ось пара матеріалів для детальнішого ознайомлення:

Java 12

Минає півроку, і ми бачимо наступний ступінь еволюції Java. Значить, настав час діставати лопатку знань і копати. З 8 до 13: повний огляд версій Java.  Частина 2 - 2

Update G1

Для G1 були внесені такі покращення:
  1. Повернення виділеної пам'яті, що не використовується.

    У Java heap memory є таке поняття як пам'ять, що не використовується (або по-іншому — неактивна). У Java 12 вирішабо пофіксувати цю проблему, тепер:

    • G1 повертає пам'ять із купи в повному GC або під час паралельного циклу; G1 намагається запобігти повному GC і запускає паралельний цикл, виходячи з розподілу купи. Прийде змушувати G1 до повернення пам'яті з купи.

    Це покращення фокусується на швидкодії за рахунок автоматичного повернення пам'яті з купи в ОС, коли G1 не використовується.

  2. Переривання змішаних колекцій, коли час паузи перевищено

    G1 використовує механізм аналізу для вибору обсягу роботи, необхідного для збирання сміття. Він збирає живі об'єкти без зупинки після визначення набору та запуску очищення. Це призводить до того, що збирач сміття перевищує цільове значення часу паузи. Власне, таку проблему і вирішує поліпшення, оскільки якщо виконання наступного кроку виходить за рамки розумного, цей крок можна перервати.

Microbenchmark

У Java 12 ввели тести мікробенчмаркінгу, щоб продуктивність JVM легко тестувалася за допомогою вже існуючих тестів. Це було б дуже корисно для всіх, хто хоче працювати над JVM. Тести, що додаються, створюються з використанням Java Microbenchmark Harness (JMH). Ці тести дозволяють проводити безперервне тестування продуктивності JVM. JEP 230 пропонує запровадити близько 100 тестів, причому нові тести вводяться у міру випуску нових версій Java. Ось приклад доданих тестів .

Shenandoah

Це алгоритм складання сміття (GC), мета якого – гарантувати низький час відгуку (нижня межа – 10-500 мс). Це зменшує час паузи GC під час роботи з очищення одночасно з працюючими потоками Java. У Shenandoah час паузи не залежить від розміру купи. Це означає, що час паузи буде однаковим незалежно від розміру вашої купи. Це експериментальна функція , яка не включена до стандартної (Oracle) збірки OpenJDK.

Improve Switch

У Java 12 покращено вирази Switch для зіставлення зі зразком. Введено новий синтаксис L →. Ось список ключових моментів нового switch :
  1. Новий синтаксис усуває потребу в операторі break для запобігання помилкам.
  2. Вирази перемикача більше не провалюються.
  3. Крім того, ми можемо визначити кілька констант в одній мітці.
  4. default регістр тепер є обов'язковим у виразах перемикачів.
  5. break використовується у виразах Switch для повернення значень із самого регістру (по суті switch може повертати значення).
Розглянемо як приклад:
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.";
  }
};
Definitive Guide To Switch Expressions In Java 13 Інші нововведення:
  1. String:

    transform(Function f)- застосовує надану функцію до рядка. Результат може бути рядком.
    indent(int x)— додає x прогалин у рядок. Якщо параметр від'ємний, то ця кількість початкових прогалин буде видалена (якщо це можливо).

  2. Files- відхопив такий метод як mismatch(), який, у свою чергу, знаходить і повертає позицію першого байта, що не збігається, у вмісті двох файлів або -1L, якщо немає невідповідності.

  3. З'явився новий клас —CompactNumberFormat для форматування десяткового числа в компактній формі. Приклад такої компактної форми — 1M замість 1000000. Таким чином, потрібно лише два-два замість дев'яти символів.

  4. Існує також новий enum , NumberFormatStyle, який має два значення - LONG і SHORT.

  5. InputStream отримав спосіб - skipNBytes(long n) : пропустити n-е кількість байтів з вхідного потоку.

Цікаві посилання на Java 12:

Java 13

Світ не стоїть на місці, рухається, розвивається, як і Java - Java 13. З 8 до 13: повний огляд версій Java.  Частина 2 - 3

Text block

Java завжди трохи страждала від визначення рядків. Якщо нам потрібно визначити рядок з пробілом, перенесення рядка, лапку або ще щось, це викликало деякі труднощі, так доводилося використовувати спеціальні символи: наприклад, \n для перенесення рядка, або екранувати деякі з рядка. Це істотно знижує читання коду, і займає зайвий час під час написання такого рядка. Це стає особливо помітним під час написання рядків, що відображають JSON, XML, HTML тощо. У результаті, якщо ми хочемо написати невеликий Json, це буде виглядати якось так:
String JSON_STRING = "{\r\n" + "\"name\" : \"someName\",\r\n" + "\"site\" : \"https://www.someSite.com/\"\r\n" + "}";
І тут на сцену виходить Java 13 і пропонує нам своє рішення у вигляді потрійних подвійних лапок до та після тексту (які й обізвали текстовими блоками). Давайте розглянемо попередній приклад json з використанням цього нововведення:
String TEXT_BLOCK_JSON = """
{
    "name" : "someName",
    "site" : "https://www.someSite.com/"
}
""";
В рази простіше і наочніше, чи не так? Також було Stringдодано три нових методи, відповідно, для управління даними блоками:
  • stripIndent(): видаляє випадкові пробіли з рядка. Це корисно, якщо ви читаєте багаторядкові рядки і хочете застосувати такий самий виняток випадкових прогалин, як це відбувається з явним оголошенням (по суті імітує компілятор для видалення випадкових прогалин);
  • formatted(Object... args ): аналог format(String format, Object... arg), але для текстових блоків;
  • translateEscapes(): повертає рядок з escape-послідовностями (наприклад \r), переведеними у відповідне значення Unicode.

Improve Switch

Вирази-перемикачі були введені Java 12, а 13 уточнює їх. У 12 ви визначаєте значення, що повертаються за допомогою break. У 13 значення, що повертається замінабо на yield. Тепер вираз зі switch, який був у нас у розділі Java 12, можна переписати як:
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.";
  }
};
Хоча нам програмістам, вже знайомим з Java, було нормально прийняти break, але це було досить дивно. Що break true намагається мені сказати? Нове (умовно нове) ключове слово yield більш зрозуміле, і в майбутньому воно може з'явитися в інших місцях, де повертаються значення. Кому глибоко цікава ця тема, рекомендую ознайомитися з цими матеріалами:

Dynamic CDS Archives

CDS - Class-Data Sharing. Дозволяє упаковувати набір класів, що часто використовуються, в архів, який пізніше може бути завантажений кількома екземплярами JVM. Навіщо це нам? Справа в тому, що в процесі завантаження класів JVM робить досить багато ресурсозатратних дій, таких як читання класів, збереження їх у внутрішніх структурах, перевірка правильності прочитаних класів, пошук і завантаження залежних класів і т. д., і лише після цього класи готові до роботи. Зрозуміло, даремно витрачається велика кількість ресурсів, адже екземпляри JVM часто можуть завантажувати одні й самі класи. Наприклад String, LinckedList, Integer. Ну чи класи одного й того ж додатка, а все це — ресурси. Якби ми виконали всі необхідні дії лише один раз і після помістабо перероблені класи до архіву, який може бути завантажений в пам'ять кількох JVM, це могло б суттєво заощадити місце в пам'яті та скоротити час запуску програми. Власне, CDS дає змогу створити саме такий архів. Java 9 дозволяла додавати до архіву лише системні класи. Java 10 - включати в архів класи програми. Створення такого архіву складається з:
  • створення списку класів, що завантажуються додатком;
  • створення так необхідного нам архіву зі знайденими класами.
Нововведення в Java 13 покращує CDS так, щоб він міг створювати архів після завершення програми. Це означає, що наведені вище два кроки тепер будуть об'єднані в один. І ще один важливий момент: тільки класи, завантажені під час роботи програми, будуть додані в архів. Іншими словами, ті класи, які все ж таки містяться в application.jar, але з якихось причин не були завантажені, не додадуться в архів.

Update Socket API

API Socket ( java.net.Socket і java.net.ServerSocket ) - по суті невід'ємна частина Java з моменту її появи, але при цьому сокети жодного разу не апдейтабо за останні двадцять років. Написані на C і Java, вони були дуже громіздкими і складними в обслуговуванні. Але Java 13 вирішила внести свої корективи в цю справу і замінила базову реалізацію. Тепер замість PlainSocketImpl інтерфейс провайдера замінюється на NioSocketImpl . Ця нова кодована реалізація ґрунтується на тій самій внутрішній інфраструктурі, що й java.nio. По суті, клас використовує механізм буферного кешу та блокування java.util.concurrent (які є сегментними), а не синхронізовані методи. Він більше не вимагає нативного коду, тим самим спрощуючи портування на різні платформи. Тим не менш, у нас є спосіб повернутися до використання PlainSocketImpl , але відтепер по дефолту використовується NioSocketImpl .

Memory Return for ZGC

Як ми пам'ятаємо, Z Складальник сміття ввели в Java 11 як механізм складання сміття з малою затримкою, щоб GC пауза ніколи не перевищувала 10 мс. Але при цьому, на відміну від інших віртуальних GC HotSpot, таких як Shenandoah та G1, він міг повертати невикористану динамічну пам'ять у ОС. Ця модифікація додає цю можливість J ZGC. Відповідно, ми отримуємо зменшений обсяг пам'яті разом з покращенням продуктивності, і ZGC тепер повертає не зафіксовану пам'ять операційній системі за умовчанням, доки не буде досягнуто зазначеного мінімального розміру купи. І ще: у ZGC тепер є максимальний розмір купи 16 ТБ, що підтримується. Раніше 4ТБ було межею. Інші нововведення:
  1. javax.security- Додано властивість jdk.sasl.disabledMechanismsдля відключення механізмів SASL.
  2. java.nio- Доданий метод FileSystems.newFileSystem (Path, Map <String,?>)- відповідно, для створення нового файлу.
  3. Класи java.nioтепер мають абсолютні (на відміну від відносних) getта set-методи. Вони, як і базовий абстрактний клас Buffer, включають метод slice()вилучення частини буфера.
  4. Додані javax.xml.parsersметоди для створення екземплярів фабрик DOM і SAX (з підтримкою просторів імен).
  5. Підтримка Unicode оновлено до версії 12.1.
Цікаві посилання на Java 13:

Підсумки

Ми могли б і пройтися за заявленими нововведеннями в Java 14, але оскільки вона незабаром побачить світ - випуск JDK 14 запланований на 17 березня 2020 року, найкраще буде провести окремий, повноцінний огляд на неї вже безпосередньо після виходу. Ще хотілося б звернути увагу на те, що в інших мовах програмування з великими перервами між випусками, як, наприклад, у Python 2–3, немає сумісності: тобто якщо код написаний на Python 2, потрібно буде добряче попотіти, перекладаючи його на 3. Java — особлива щодо цього, оскільки вона надзвичайноназад сумісна. Це означає, що ваша програма на Java 5 або 8 гарантовано працюватиме з віртуальною машиною Java 8-13 - з деякими винятками, про які вам зараз не потрібно турбуватися. Зрозуміло, що це не працює навпаки: наприклад, якщо ваша програма юзає функції Java 13, які просто недоступні в Java 8 JVM. На цьому у мене сьогодні все, тим хто дочитав до цього місця респект)) З 8 до 13: повний огляд версій Java.  Частина 2 - 5
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ