Вышла Java 19

от автора

Вышла общедоступная версия Java 19. В этот релиз попало более двух тысяч закрытых задач и 7 JEP’ов. Release Notes можно посмотреть здесь. Изменения API – здесь.

Ссылки на скачивание:

Вот список JEP’ов, которые попали в Java 19.

Паттерн-матчинг для switch (Third Preview) (JEP 427)

Паттерн-матчинг для switch, который появился в Java 17 в режиме preview и остался на второе preview в Java 18, всё ещё остаётся в этом статусе. Это первый случай в Java, когда языковой конструкции не хватило двух релизов, чтобы стать стабильной: ранее все конструкции укладывались в два preview.

В этом релизе в паттерн-матчинг было внесено два главных изменения.

Во-первых, охранные паттерны && были заменены на условия when:

// --enable-preview --release 18: switch (obj) {     case Integer x && x > 0 -> ...;     default -> ...; }

// --enable-preview --release 19: switch (obj) {     case Integer x when x > 0 -> ...;     default -> ...; }

О мотивации такого изменения можно прочитать в рассылке проекта Amber.

Во-вторых, было изменено поведение матчинга null. Теперь null матчится только в ветке case null и большие ни в каких других, включая тотальных:

// --enable-preview --release 18: Object obj = null; switch (obj) {     case Object x -> ...; // matches because total pattern }

// --enable-preview --release 19: Object obj = null; switch (obj) {     case Object x -> ...; // NPE }

// --enable-preview --release 19: Object obj = null; switch (obj) {     case null -> ...; // OK     case Object x -> ...;  }

Про причины такого изменения можно также прочитать в рассылке.

Паттерны записей (Preview) (JEP 405)

Паттерн-матчинг дополнился новым видом паттерна: паттерн записей.

Раньше для паттерн-матчинга записей был доступен только паттерн по типу с дальнейшим ручным извлечением компонентов:

record Point(int x, int y) {}  static void printSum(Object o) {     if (o instanceof Point p) {         int x = p.x();         int y = p.y();         System.out.println(x + y);     } }

С паттернами записей код становится существенно компактнее:

static void printSum(Object o) {     if (o instanceof Point(int x, int y)) {         System.out.println(x + y);     } }

Паттерны записей могут быть вложенными:

record Point(int x, int y) {} enum Color { RED, GREEN, BLUE } record ColoredPoint(Point p, Color c) {}  static void printCoordinatesAndColor(ColoredPoint cp) {     if (cp instanceof ColoredPoint(Point(var x, var y), var c)) {         System.out.println("x = " + x);         System.out.println("y = " + y);         System.out.println("color = " + c);     } }

Также паттерны записей могут быть именованными:

static void printObject(Object obj) {     if (obj instanceof Point(var x, var y) p) {         System.out.println("point = " + p);         System.out.println("x = " + x);         System.out.println("y = " + y);     } }

Кроме того, паттерны записей хорошо сочетаются со switch из предыдущего JEP’а:

static void printObject(Object obj) {     switch (obj) {         case Point(var x, var y) when x > 0 && y > 0 ->             System.out.println("Positive point: x = " + x + ", y = " + y);         case Point(var x, var y) ->             System.out.println("Point: x = " + x + ", y = " + y);         default -> System.out.println("Other");     } }

Virtual Threads (Preview) (JEP 425)

В Java появились виртуальные потоки в режиме preview.

Виртуальные потоки, в отличие от потоков операционной системы, являются легковесными и могут создаваться в огромном количестве (миллионы экземпляров). Это свойство должно значительно облегчить написание конкурентных программ, поскольку позволит применять простой подход «один запрос – один поток» и не прибегать к более сложному асинхронному программированию. При этом миграция на виртуальные потоки уже существующего кода должна быть максимально простой, потому что виртуальные потоки являются экземплярами существующего класса java.lang.Thread, а значит, большую часть существующего кода не придётся переписывать.

Виртуальные потоки реализованы поверх обычных потоков и существуют только для JVM, но не для операционной системы (отсюда и название «виртуальные»). Поток, на котором в данный момент работает виртуальный поток, называется потоком-носителем. Если потоки платформы полагаются на планировщик операционной системы, то планировщиком для виртуальных потоков является ForkJoinPool. Когда виртуальный поток блокируется на некоторой блокирующей операции, то он размонтируется от своего потока-носителя, что позволяет потоку-носителю примонтировать другой виртуальный поток и продолжить работу. Такой режим работы и малый размер виртуальных потоков позволяет им очень хорошо масштабироваться. Однако на данный момент есть два исключения: synchronized блоки и JNI. При их выполнении виртуальный поток не может быть размонтирован, поскольку он привязан к своему потоку-носителю. Такое ограничение может препятствовать масштабированию. Поэтому при желании максимально использовать потенциал виртуальных потоков рекомендуется избегать synchronized блоки и операции JNI, которые выполняются часто или занимают длительное время.

Для создания виртуальных потоков и работы с ними появилось следующее API:

  • Thread.Builder – билдер потоков. Например, виртуальный поток можно создать путём вызова Thread.ofVirtual().name("name").unstarted(runnable).
  • Thread.startVirtualThread(Runnable) – создаёт и сразу же запускает виртуальный поток.
  • Thread.isVirtual() – проверяет, является ли поток виртуальным.
  • Executors.newVirtualThreadPerTaskExecutor() – возвращает исполнитель, который создаёт новый виртуальный поток на каждую задачу.

Для виртуальных потоков также добавилась поддержка в дебаггере, JVM TI и Java Flight Recorder.

Виртуальные потоки разрабатываются с 2017 года в рамках проекта Loom.

Structured Concurrency (Incubator) (JEP 428)

Ещё одним результатом работы над проектом Loom стало добавление в Java нового API для Structured Concurrency.

Structured Concurrency – это подход многопоточного программирования, который заимствует принципы из однопоточного структурного программирования. Главная идея такого подхода заключается в следующем: если задача расщепляется на несколько конкурентных подзадач, то эти подзадачи воссоединяются в блоке кода главной задачи. Все подзадачи логически сгруппированы и организованы в иерархию. Каждая подзадача ограничена по времени жизни областью видимости блока кода главной задачи.

В центре нового API класс StructuredTaskScope. Пример использования StructuredTaskScope, где показана задача, которая параллельно запускает две подзадачи и дожидается результата их выполнения:

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      return new Response(user.resultNow(), order.resultNow()); }

Может показаться, что в точности аналогичный код можно было бы написать с использованием ExecutorService и submit(), но у StructuredTaskScope есть несколько принципиальных отличий, которые делают код безопаснее:

  • Время жизни всех потоков подзадач ограничено областью видимости блока try-with-resources. Метод close() гарантированно не завершится, пока не завершатся все подзадачи.
  • Если одна из операций findUser() и fetchOrder() завершается ошибкой, то другая операция отменяется автоматически, если ещё не завершена (в случае политики ShutdownOnFailure, возможны другие).
  • Если главный поток прерывается в процессе ожидания join(), то обе операции findUser() и fetchOrder() отменяются.
  • В дампе потоков будет видна иерархия: потоки, выполняющие findUser() и fetchOrder(), будут отображаться как дочерние для главного потока.

Новое API должно облегчить написание многопоточных программ благодаря знакомому структурному подходу. Пока API имеет инкубационный статус, оно будет находиться в модуле jdk.incubator.concurrent и одноимённом пакете.

Foreign Function & Memory API (Preview) (JEP 424)

Foreign Function & Memory API, которое было в инкубационном статусе в Java 17 и Java 18, теперь стало Preview API. Оно находится в пакете java.lang.foreign.

Vector API (Fourth Incubator) (JEP 426)

Векторное API, которое уже было в инкубационном статусе три релиза (Java 16, Java 17, Java 18), продолжает в нём находиться. Пока API не выйдет из инкубационного статуса, оно будет находиться в модуле jdk.incubator.vector.

Linux/RISC-V Port (JEP 422)

JDK теперь официально портирован под архитектуру Linux/RISC-V.

Заключение

Java 19 не является LTS-релизом и будет получать обновления от Oracle только в течение полугода (до марта 2023 года). Однако Azul обещает выпускать обновления Zulu как минимум до марта 2025 года (2.5 года).


ссылка на оригинал статьи https://habr.com/ru/post/689344/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *