Список JEP-ов JDK 17 уже стабилен и содержит ряд интересных изменений, хочу о них поделится в этой публикации.

Установить JDK 17 можно уже по ссылке или с использованием SDKMan:

sdk install java 17.ea.30-open

А теперь подробней о каждом JEP и как он повлиял на Java 17.

JEP 306: Restore Always-Strict Floating-Point Semantics

В 90х была проблема связанная с семантикой операций с плавающей запятой при взаимодействии Java с JVM работающей на базе популярной архитектуры x86, которая имела некоторые проблемы связанные с некоторым набором команд процессора с плавающей запятой.

И чтобы соответствовать точной семантике с плавающей запятой в Java SE 1.2 было решено пересмотреть устройство семантики с плавающей запятой по умолчанию для x86, что требовало дополнительных накладных расходов.

Однако, позже было разработано расширение SSE2 (Streaming SIMD Extensions 2), которое поставлялось в процессорах Pentium 4 и более поздних версиях. Они могли поддерживать строгие операции с плавающей запятой JVM без чрезмерных накладных расходов.

И поскольку Intel и AMD уже давно поддерживает SSE2 которые обеспечивают естественную поддержку строгой семантики с плавающей запятой, то потребности в поддержки семантики с плавающей запятой отличной от строгой больше нет. И в JEP 306 было решено ее убрать.

JEP 356: Enhanced Pseudo-Random Number Generators

В этом JEP представлен новый интерфейс RandomGenerator и реализации для генераторов псевдослучайных чисел (PRNG):

  • SplittableRandomGenerator расширяет RandomGenerator, а также предоставляет методы split и splits, которые позволяют пользователю создавать новые RandomGenerator из уже существующего RandomGenerator, который обычно дает статистически независимые результаты.

  • JumpableRandomGenerator расширяет RandomGenerator, а также предоставляет методы jump и jumps, которые позволяют продвигаться вперед на небольшое количество генераций.

  • LeapableRandomGenerator расширяет RandomGenerator, а также предоставляет методы leap и leaps, которые позволяют продвигаться вперед на большое количество генераций.

  • ArbitrarilyJumpableRandomGenerator расширяет RandomGenerator, а также предоставляет методы jump и jumps, которые позволяют указать количество произвольных генераций.

Основная идея состоит в том, чтобы упростить переключение между различными алгоритмами PRGN, удалить дублирующий код в существующих PRGN, обеспечить лучшую поддержку stream-based программирования и при этом всем сохранить текущее поведение java.util.Random.

JEP 382: New macOS Rendering Pipeline

В сентябре 2018 года Apple отказалась от OpenGL в macOS 10.14. Так как Apple позиционирует Metal фреймворк заменой OpenGL, который в свою очередь обладает превосходной производительностью, было решено для новой реализации поддержки Java 2D API взять именно Metal фреймворк. И в JDK 17 для macOS выше 10.14 Java 2D будет использовать Metal фреймворк.

JEP 391: macOS/AArch64 Port

Так как в Apple было принято решение на долгосрочный переход компьютеров серии Macintosh c процессоров архитектуры x64 на AArch64, то для JDK появляется необходимость в портировании как ранее было сделано для Linux на базе AArch64.

Значит ли это, что Java не будет работать на AArch64? Нет, так как Apple предоставила Rosetta 2, которая одноразово переведет байт код работающий под x64 на новый, который будет понимать AArch64, но момент ретрансляции займет дополнительное время и ресурсы.

Этот JEP позволяет выполнять Java код нативно на базе AArch64 без использования Rosetta 2.

JEP 398: Deprecate the Applet API for Removal

Applet API уже довольно давно устарел и почти все популярные браузеры удалили его поддержку либо объявили о его скором удалении.

В Java 9 в JEP 289 Applet API был помечен как устаревший но пока еще без пометки на удаление в будущих версиях. В Java 17 Applet API помечен на удаление и будет удален в последующих релизах Java.

JEP 403: Strongly Encapsulate JDK Internals

В Java 16 был установлен параметр по умолчанию, который позволял контролировать возможность доступа к внутренним API и пакетам JDK.

В Java 17 этот параметр был удален и возможность ослабить строгую инкапсуляцию внутренних частей полностью отсутствует.

JEP 406: Pattern Matching for switch (Preview)

В Java 16 была добавлен Pattern Matching для оператора instanceof подробней можно ознакомится тут. Java 17 представляет на предварительный просмотр Pattern Matching для конструкции switch.

Например, ранее мы бы написали следующий код так:

static String formatter(Object o) {
  String formatted = "unknown";
  if (o instanceof Integer i) {
    formatted = String.format("int %d", i);
  } else if (o instanceof Long l) {
    formatted = String.format("long %d", l);
  } else if (o instanceof Double d) {
    formatted = String.format("double %f", d);
  } else if (o instanceof String s) {
    formatted = String.format("String %s", s);
  }

  return formatted;
}

Но для решения подобного рода задач в разы приятней и лучше подошла бы конструкция switch, что Java 17 нам и предложила:

static String formatterPatternSwitch(Object o) {
  return switch (o) {
    case Integer i -> String.format("int %d", i);
    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        -> o.toString();
  };
}

Также ранее switch бросал исключение в случае, когда передаваемый параметр был null, и чтобы исключить такую возможность мы делали проверку на null:

static void testFooBar(String s) {
  if (s == null) {
    System.out.println("oops!");
    return;
  }
  switch (s) {
    case "Foo", "Bar" -> System.out.println("Great");
    default           -> System.out.println("Ok");
  }
}

Теперь же, все проще и необходимости проверять параметр на null не нужен:

static void testFooBar(String s) {
  switch (s) {
    case null         -> System.out.println("Oops");
    case "Foo", "Bar" -> System.out.println("Great");
    default           -> System.out.println("Ok");
  }
}

Больше примеров использования Pattern Matching для switch можно найти тут.

JEP 407: Remove RMI Activation

В Java 15 механизм активации RMI был помечен как устаревший и возможен к удалению в будущих версиях. И в Java 17 в JEP 407 он был полностью удален.

JEP 409: Sealed Classes

В Java 16 был представлен второй предварительный просмотр Sealed классов и вот в Java 17 они выходят со стадии предварительного просмотра и становятся частью JDK начиная с 17 версии.

Более подробно с новой функциональностью вы можете познакомится тут.

Sealed классы или интерфейсы ограничивают доступ к их расширению или реализации посредством явного указания классов/интерфейсов которым это разрешено.

public sealed class Animal permits Dog, Cat, Monkey { ... }

JEP 410: Remove the Experimental AOT and JIT Compiler

В Java 9 в качестве экспериментальной функции был добавлен инструмент jaotc позволяющий выполнять ahead-of-time (AoT) compilation позволяющий ускорить запуск Java приложений. Инструмент использует компилятор Graal.

По причине малой активности использования данного инструмента и больших усилий на его поддержку было принято решение удалить его с JDK 17.

JEP 411: Deprecate the Security Manager for Removal

В релизе Java 1.0 был добавлен Security Manager, который уже длительное время никем не используется. В Java 17 Security Manager помечен как устаревший и будет удален в последующих версиях вместе с Applet API.

JEP 412: Foreign Function & Memory API (Incubator)

Этот JEP является эволюцией двух ранее созданных API-интерфейсов: Foreign-Memory Access API и Foreign Linker API, которые ранее был представлены в Java 14, 15 и 16.

JEP 414: Vector API (Second Incubator)

Первый предварительный просмотр был представлен в Java 16. Java 17 представляет к нашему вниманию второй предварительный просмотр, где Vector API был улучшен с точки зрения производительности и реализации, включая улучшения для преобразования байтовых векторов в логические массивы из них.

JEP 415: Context-Specific Deserialization Filters

Десериализация ненадежных данных - операция, которая по своей сути рискованна, потому что содержимое входящих потоков данных во многих случаях получается через неизвестного или не прошедшего проверку подлинности клиента.

Ключом к предотвращению атак сериализации является запрет десериализации экземпляров произвольных классов, что предотвращает выполнение их методов прямо или косвенно. Злоумышленник может запустить код любого класса с плохими намерениями, тщательно сконструировав поток.

В Java 9 были представлены фильтры десериализации, чтобы код приложения и библиотеки мог проверять входящие потоки данных перед их десериализацией. Такой код предоставляет логику проверки в виде java.io.ObjectInputFilter, когда он создает поток десериализации.

Так вот каждый раз, когда создается ObjectInputStream, его фильтр для каждого потока инициализируется как статический фильтр для всей JVM и при желании этот фильтр для каждого потока позже может быть изменен на другой фильтр.

В этом JEP представляется настраиваемая фабрика фильтров для всего JVM. Каждый раз, когда создается ObjectInputStream, его фильтр для каждого потока инициализируется значением, возвращаемым путем вызова статической фабрики фильтров для всей JVM.

Таким образом, эти фильтры являются динамическими и зависят от контекста, в отличие от единственного статического фильтра десериализации для всей JVM. Для обратной совместимости, если фабрика фильтров не задана, встроенная фабрика возвращает статический фильтр для всей JVM, если он был настроен.

Источники

Комментарии (6)


  1. csl
    15.07.2021 12:09
    +1

    Keyword strictfp ещё нужен?


    1. axbarchuk Автор
      15.07.2021 12:16

      Уже в нем нет нужды и в JDK 17 линтинг будет выдавать ворнинг при его наличии.


  1. johndow
    16.07.2021 12:02
    +1

    возможность ослабить строгую инкапсуляцию внутренних частей полностью отсутствует.


    ну здрасьте! к счастью нет. иначе на 17-ую дооолго никто не перейдёт.

    The sun.misc and sun.reflect packages will still be exported by the jdk.unsupported module, and will still be open so that code can access their non-public elements via reflection. No other JDK packages will be open in this way.

    It will still be possible to use the --add-opens command-line option, or the Add-Opens JAR-file manifest attribute, to open specific packages.


    1. csl
      16.07.2021 12:16
      +1

      Вожможность ослабить строгую инкапсуляцию средствами языка отсутствует. Рефлексия уже за рамками (в том числе и из соображений производительности).


      1. johndow
        16.07.2021 12:49
        +1

        Причём здесь средства языка и рефлексия? В Java 17 просто жёстко закрепили поведение Java 16 --illegal-access=deny. Но также как и в 9-16 никто не мешает добавить opens/exports в запуск или в манифест.


        1. csl
          16.07.2021 12:53

          Об opens/exports и не подумал, посыпаю голову пеплом…