Новые фичи и улучшения в предстоящем LTS-релизе Axiom JDK 21

eg    /    Онлайн

Хотя срок выпуска релизов с долгосрочной поддержкой (LTS) сократился до двух лет, с момента появления LTS JDK 17 в Java накопилось много значимых улучшений. LTS-версия 21, которая выйдет в сентябре, включает 15 JEP с новыми, финализированными и улучшенными фичами. Предлагаем поближе познакомиться с предстоящим релизом, ведь возможно, что именно с этой версией вы будете работать ближайшие годы!

Новый функционал

JEP 430: Строковые шаблоны (Preview)

Строковые шаблоны (string templates) — это фича и API в режиме preview. Она призвана упростить строковые выражения со значениями, вычисляемыми во время выполнения программы. Механизмы конкатенации буквенного текста и выражений, которые до этого использовались в Java, на выходе давали трудный для восприятия код. В других языках для этих целей используется интерполяция строк: она позволяет сократить код, но при этом повышает риски безопасности.

Шаблонные выражения сочетают в себе лаконичность интерполяции и высокую безопасность.

Взгляните на сниппет кода с шаблонным выражением на второй строке:

String name = "Joan";
String info = STR."My name is \{name}";
assert info.equals("My name is Joan");   // true

Выражение включает в себя обработчик шаблонов STR, точку и шаблон со встроенным выражением \{name}. Встроенными выражениями могут быть строки, но выражения также могут выполнять арифметические операции, вызывать методы, получать доступ к полям и даже занимать несколько строк кода.

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

JEP 431: Последовательные коллекции

Последовательные коллекции (sequenced collections) позволят разработчикам использовать коллекции, для которых определен порядок элементов, и универсальные API для получения доступа к первому и последнему элементам и обработки элементов в прямом и обратном порядке.

Три новых интерфейса — sequenced collections, sets и maps — будут приведены в соответствие с текущей иерархией Collections. У всех этих интерфейсов есть новые методы, облегчающие процесс разработки:

  • В sequenced collection есть метод reversed() для просмотра коллекции в обратном порядке, обработки элементов в обоих направлениях и выполнения всех привычных итераций, таких как forEach()stream() и т.д.
  • Sequenced set включает методы addFirst(E) и addLast(E), которые могут перемещать элементы в определенное место, если они уже есть в set.
  • В sequenced map есть методы put*(K, V), похожие на методы add*(E) в sequenced sets.

JEP 443: Безымянные паттерны и переменные (Preview)

Безымянные паттерны и переменные (unnamed patterns and variables) улучшают читаемость и поддержку кода благодаря тому, что теперь не нужно указывать тип и имя компонента record при сопоставлении паттернов (pattern matching). Они также позволяют идентифицировать переменные, которые необходимо объявить, но которые при этом не используются.

В обоих случаях будет использоваться символ нижнего подчеркивания _ .

Безымянные паттерны позволят разработчикам не указывать неиспользуемые компоненты в record patterns, например,

  • ... instanceof Point(int x, _)
  • case Point(int x, _)

Безымянные переменные заменяют имена неиспользуемых переменных (например, в блоках try-with-resources или try-catch):

  • int _ = q.remove();
  • ... } catch (NumberFormatException _) { ...
  • (int x, int _) -> x + x

JEP 445: Безымянные классы и main методы экземпляра класса (Preview)

Разработчикам, которые только начинают знакомство с Java, фичи, используемые в корпоративной разработке, могут показаться слишком сложными. JEP 445 (unnamed classes and instance main methods) даст возможность писать простые программы, состоящие из одного класса, а затем постепенно расширять их по мере изучения языка. Данная фича также будет полезна опытным разработчикам, которым нужно писать лаконичные приложения без компонентов, используемых для программирования крупных систем.

Например, базовая программа HelloWorld содержит несколько элементов, которые не нужны на начальном этапе изучения, но которые трудно понять:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Теперь код можно упростить:

void main() {
    System.out.println("Hello, World!");
}

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

JEP 451: Подготовка к запрету динамической загрузки агентов

При использовании JDK 21 разработчики будут получать предупреждения в случае динамической загрузки агентов в запущенную JVM. JEP 451 (prepare to disallow the dynamic loading of agents) закладывает основу для запрета использования динамической загрузки агентов по умолчанию, что соответствует общей концепции по повышению целостности Java.

Агенты — это компоненты, которые могут изменять код во время выполнения программы. Иногда они используются служебными инструментами, такими как профайлеры и отладчики, но разработчик должен дать им разрешение на изменение приложения. Однако некоторые библиотеки, использующие агенты, могут обойти это требование и бесшумно внедрить агента в запущенную JVM, что повышает риски безопасности.

В будущем пользователь должен будет явно разрешить динамическую загрузку посредством флага -XX:+EnableDynamicAgentLoading. К счастью, большинство распространенных служебных инструментов не используют динамическую загрузку агентов, а значит, это изменение их не затронет. Что касается библиотек, они должны будут загружать агент при запуске приложения при условии использования параметров -javaagent/-agentlib. Разработчикам библиотек рекомендуется дополнить документацию описанием того, как загружать агенты при запуске.

JEP 452: API для механизма инкапсуляции ключа

API для механизма инкапсуляции ключа (Key Encapsulation Mechanism, KEM) позволит использовать новый метод шифрования для защиты симметричных ключей посредством асимметричной криптографии (с открытым ключом). KEM использует свойства открытого ключа для создания симметричного ключа без заполнения блока данных неинформативными символами.

На данный момент в Java нет стандартного API для KEM. Однако это важный современный метод защиты от кибератак, который, скорее всего, будет включен в следующее поколение стандартных алгоритмов криптографии с открытым ключом.

Финализированные фичи

Эти фичи были включены в предыдущие версии, и после череды улучшений финализированы в этом LTS релизе.

JEP 440: Record Patterns

Record patterns, которые используются для деконструкции структурных значений с целью улучшения механизма pattern matching, появились в JDK 19. JEP 440 финализирует фичу с некоторыми улучшениями на основании отзывов от разработчиков, наиболее важное из которых — удаление поддержки record patterns в хедере улучшенного оператора for.

JEP 441: Pattern Matching для switch

Функция pattern matching для выражений и операторов switch была предложена в JDK 17 и улучшена в последующих релизах. Ее цель — расширение гибкости и повышение безопасности операторов switch. Благодаря pattern matching для switch разработчики могут тестировать выражения по ряду шаблонов, благодаря чему сложные запросы данных становятся более лаконичными и надежными. Финализированная фича включает в себя несколько изменений:

  • Удаление паттернов в круглых скобках;
  • Возможность использовать квалифицированные константы enum в качестве констант case в switch.

JEP 444: Виртуальные потоки

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

Виртуальные потоки вошли в JDK 19 в качестве preview API. JEP 444 финализирует фичу с несколькими улучшениями:

  • Поддержка локальных переменных потока из ThreadLocal API по умолчанию, что позволяет разработчикам хранить данные, доступные только определенному потоку;
  • Виртуальные потоки, созданные с помощью Thread.Builder API, теперь по умолчанию можно мониторить в течение жизненного цикла. Также можно выполнять мониторинг с помощью дампа кучи, в котором многочисленные виртуальные потоки удобно группируются.

Улучшенные фичи

JEP 439: ZGC, учитывающий поколения

ZGC — это масштабируемый сборщик мусора с низким временем отклика и стабильно короткими паузами вне зависимости от размера кучи. Однако текущий ZGC не учитывает поколения и хранит молодые и старые объекты вместе, поэтому ему приходится собирать все объекты сразу. Поскольку большинство объектов “умирают” молодыми, а старые “живут” дольше, на сборку молодых уходит меньше ресурсов, и при этом высвобождается больше памяти.

Таким образом, ZGC, учитывающий поколения, будет хранить молодые и старые объекты в разных областях и чаще собирать молодые объекты, что уменьшит оверхед CPU и кучи при сборке мусора.

JEP 442: Foreign Function & Memory API (третий Preview)

Foreign function & memory API позволяет Java приложениям взаимодействовать с кодом и данными вне среды исполнения Java в безопасном режиме. FFM API призван заменить Java Native Interface более надежной моделью, разработанной специально для Java.

Это третий preview фичи FFM API, включающий следующие изменения:

  • Централизованное управление жизненным циклом нативных сегментов посредством интерфейса Arena;
  • Улучшенные пути раскладок с новым элементом для обращения к адресным раскладкам;
  • Новая опция линкера для оптимизации вызовов функций с коротким жизненным циклом без вызова Java;
  • Имплементация нового альтернативного нативного линкера на базе libffi для упрощения портирования;
  • Удален класс VaList.

JEP 446: Scoped Values (Preview)

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

Scoped values рекомендуется использовать вместо локальных переменных потока, потому что scoped values неизменяемые, не такие сложные и потребляют меньше памяти.

Эта фича была введена в JDK 20 в режиме incubator, теперь это preview API.

JEP 448: Vector API (шестой Incubator)

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

Это шестой incubator с фиксами и значимыми изменениями:

  • Добавление исключающих или (xor) операций к векторным маскам;
  • Улучшенная производительность векторных перемещений, особенно при перераспределении элементов вектора и конвертации между векторами.

JEP 453: Структурная многопоточность (Preview)

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

Фича была включена в JDK 19 в качестве incubating API, и была повторно инкубирована в последующих релизах. Это preview API с одним значимым изменением: метод StructuredTaskScope::fork(...) возвращает [Subtask] вместо Future. Future более полезен при работе с множеством задач как с индивидуальными задачами, а не целостной единицей работы (что является целью структурной многопоточности). При использовании Future вызывается метод get(), который блокируется до тех пор, пока не будет доступен результат. Это контрпродуктивно при использовании StructuredTaskScope, который теперь будет использовать никогда не блокирующийся метод resultNow().

Фичи, объявленные устаревшими

JEP 449: Подготовка порта Windows 32-bit x86 к удалению

Конец срока эксплуатации последней версии ОС Windows, которая поддерживает 32-битные процессоры (Windows 10), наступит в октябре 2025 года. В то же время, использование виртуальных потоков на Windows x86-32 не дает ожидаемых преимуществ. Таким образом, необходимость в порте Windows 32-bit x86 исчезает, и порт будет удален в последующих релизах.

Миграция на любую версию JDK с доверенной средой разработки Axiom JDK Pro

Вне зависимости от того, планируете ли вы в ближайшее время обновлять версию Java, команда Axiom JDK поддерживает все LTS-релизы Java (8, 11, 17), легаси 6 и 7, а также текущий релиз. Мигрируйте на любую версию Axiom JDK Pro и получайте ежеквартальные обновления безопасности, экстренные патчи и доступ к функционалу, предназначенному для российских разработчиков: доверенному репозиторию Java-библиотек, TLS-сертификатам Минцифры, а также версии Axiom JDK Certified, сертифицированной ФСТЭК по 4 ОУД.