Axiom JDK 16: ещё удобнее и мощнее

Axiom JDK 16: ещё удобнее и мощнее


Март 19, 2021


JDK 16 — последняя версия комплекта разработчика Java-приложений перед стабильным релизом с долгосрочной поддержкой (LTS). Однако это отнюдь не «проходная», а полноценная версия, где представлено 17 новых функций. Одной из них является порт Alpine Linux, разработанный компанией БЕЛЛСОФТ.

Всего в новом JDK насчитывается 3085 изменений (исправления ошибок, бэкпортирование функций и различные дополнительные задачи), среди которых 21 внесла наша команда. Отдельно подсчитаны исправления в OpenJFX, а именно 58 в текущей версии. Вместе с релизом Oracle выложила график, где наглядно виден вклад компаний-участников проекта:

Fixes per organisation

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

1. Records (JEP 395), Sealed Classes (JEP 397) и Pattern Matching for instanceof (JEP 394)

Введение в код Java™ этих трёх функций приближает нас к кодированию алгебраических типов данных. По сути, это следующая итерация проекта Amber. Во-первых, возникает новый вид объявления типов — записи, или records, впервые предложенные в JDK 14 (JEP 395). Они представляют собой простые носители неизменяемых наборов данных. Записи помогут решить проблему шаблонного кода (его также называют Java boilerplate), избавив от излишней «многословности» и «церемониальности», которые часто свойственны языкам ОПП. Во-вторых, в текущей версии представлено второе превью запечатанных (sealed) типов; с первым можно ознакомиться в JEP 360. Класс или интерфейс становится запечатанным, если объявлен модификатором области действия sealed, что ограничивает возможность его расширения другими типами. Наконец, сопоставление шаблонов (pattern matching) первоначально было представлено в рамках JEP 305 и пока только для оператора instanceof. Благодаря этой функции общая логика приложения становится более лаконичной, чистой и защищенной. Однако работа над Pattern matching еще в процессе, так что мы будем терпеливо ждать его полноценного внедрения в грядущих релизах JDK.

Если говорить в целом, сочетание функций «records + sealed classes + pattern matching» расширяет возможности Java, а описание алгоритмов становится при этом еще проще. Небольшой пример в доказательство:

// sealed requires --enable-preview --source 16
sealed interface Expr permits SumExpr, NegExpr, IntExpr { }
record SumExpr(Expr left, Expr right) implements Expr { }
record NegExpr(Expr expr) implements Expr { }
record IntExpr(int value) implements Expr { }
static int eval(Expr e) {
 // Let's wait for pattern matching for switch
 // Let's wait for records deconstruction
 if (e instanceof SumExpr se) return eval(se.left) + eval(se.right);
 if (e instanceof NegExpr ne) return -eval(ne.expr);
 if (e instanceof IntExpr ie) return ie.value;
 return 0; // Should become unnecessary (not yet in recent EA)
}

2. Vector API (JEP 338)

Одна из наиболее значимых функций в этом релизе. Однако стоит помнить, что пока векторный API находится в инкубационном модуле — используйте jdk.incubator.vector. Его интеграция обеспечит в Java поддержку кросс-платформенных вычислений с использованием параллелизма данных на уровне команд. Vector API отвечает за явную векторизацию байт-кода (в противовес нестабильной автоматической в JIT-компиляторах). Он реализует инструкции процессоров из области «тёмного кремния», с которыми ранее не могли эффективно работать виртуальная машина Java и JDK:

  • SIMD;
  • AVX on x86;
  • NEON and SVE on ARM.

Разработчики JEP ставили целью создание простого и надёжного API, который поддерживался бы на различных платформах, был предсказуем и гарантировал постепенную деградацию векторного вычисления. Он также должен быть выразительным, портативным и эффективным независимо от особенностей инструкций на архитектурах ЦП. И вот результат: векторный API позволяет производить быстрые математические вычисления на Java. Инструмент готов к работе на девайсах с чипами как Intel, так и ARM без дополнительной конфигурации.

Ожидается, что с выходом типов-значений (value types) по завершении проекта Valhalla векторный API получит бонус к производительности.

3. Alpine Linux Port (JEP 386)

Для команды инженеров БЕЛЛСОФТ выход этого порта — самое главное событие, ведь мы принимали непосредственное участие в его создании. Локальный репозиторий проекта Portola слился с основной веткой JDK, и теперь любой пользователь может самостоятельно собрать микроконтейнер с легковесным образом ОС и Java-рантаймом на свой вкус. Мы, конечно же, рекомендуем использовать среду Liberica JDK, поскольку она еще с прошлого года включает нативную поддержку Alpine Linux и обладает всеми необходимыми оптимизациями.

4. Windows/AArch64 Port (JEP 388)

Еще один JEP, интегрированный компанией-производителем собственного дистрибутива OpenJDK: на сей раз командой инженеров Microsoft. Портирование JDK на архитектуру ARM 64-bit под Windows развилось из наработок для комбинации Linux/AArch64 (JEP 237). Порт получил улучшенные внутренние функции из JEP 315 и полностью готов к использованию в продакшене.

Разумеется, для Java-сообщества перенос JDK на Windows/AArch64 был одним из самых ожидаемых нововведений. А теперь ждём новые оптимизированные сборки под эту платформу!

5. Packaging Tool (JEP 392)

До недавнего времени для запуска и использования ПО на Java было желательно установить в системе одну среду исполнения, единую для всех программ. Предполагалось, что это позволит сэкономить место на жёстком диске и уменьшить потребление трафика, поскольку вместо нового рантайма загружался только байт-код конкретного приложения. У такого подхода был и существенный минус: программы поставлялись в виде JAR-архивов. А значит, сначала нужно было поставить Java рантайм, потом JAR, а затем неким образом добавить архив в среду исполнения.

В современной разработке это считается плохим UX-дизайном. Поставщик приложения обязан предоставить пользователю инсталлятор, который подходит его платформе и ведёт себя привычным образом. Например, на Windows двойной щелчок запускает мастер установки, а в случае macOS открывается окно, где нужно перетащить файл в папку «Программы».

В JDK 16 вводится новая утилита — jpackage. Она основана на javapackager, перешедшем из Oracle JavaFX. Этот тул для упаковки автономных Java-приложений вместе со средой исполнения был впервые предложен в 14-ой версии (JEP 343) как инкубационный инструмент; теперь же он подходит для промышленной эксплуатации. Функция уже поддерживается во всех операционных системах и производит свойственные платформе файлы: msi и exe на Windows, pkg и dmg на macOS, deb и rpm на Linux.

Хотите узнать, как внедрить современный функционал из текущего релиза в своё Java-приложение? Однако не уверены, стоит ли переходить на JDK 16? Обратитесь в БЕЛЛСОФТ! Мы — одни из ведущих разработчиков кода OpenJDK, вникнем в потребности любого проекта. Опытные инженеры помогут перевести вашу организацию на новую версию Java и окажут экспертную техподдержку.

6. Elastic Metaspace (JEP 387)

С тех пор, как проект JDK перешел на открытый исходный код, сообщество разработчиков обучает сборщики мусора (garbage collectors) возвращать неиспользуемую память в операционную систему. Впервые такая функция была реализована в JDK 12 для дефолтного G1. Следом появились два новых низколатентных сборщика: масштабируемый ZGC (представлен для ознакомления в JDK 11) и низкопаузный Shenandoah GC с коротким временем отклика (впервые интегрирован в JDK 12). В JDK 15 оба инструмента сменили статус и стали официально готовы к продуктовой разработке. Оба сборщика призваны решить проблему слишком долгих пауз в Java и увеличить общую скорость отклика в облаке.

Этот JEP обращается к другой области — внутренним структурам Java-кода. Их также необходимо настроить на возврат части потребляемых ресурсов. До выхода текущей версии, когда память в метапространстве (месте хранения метаданных классов HotSpot) больше не требовалась для работы, она возвращалась в виртуальную машину Java (JVM). Однако JVM, в свою очередь, передавала память в ОС недостаточно быстро. Теперь же, с повышением эластичности метапространства, память дробится на блоки, снижая потребности загрузчика классов и фрагментацию. Неиспользуемая память быстрее возвращается в ОС, что в целом сокращает расходы организации. Мы благодарим коллег из SAP за ценный вклад в код OpenJDK!

7. Enable C++14 Language Features (JEP 347), Migrate from Mercurial to Git (JEP 357) и Migrate to GitHub (JEP 369)

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

Мы рады завершению миграции на Git и доступу к возможностям C++. Прекрасно, что современные средства программирования и рецензирования кода на GitHub наконец-то доступны всем разработчикам ядра JDK. Спасибо команде Oracle за руководство проектом Skara.

8. Strongly Encapsulate JDK Internals by Default (JEP 396)

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

Изначально такие инструменты не предназначены для внешней среды за пределами ядра JDK. Однако по разным причинам большое число приложений на Java оказалось завязано на внутренних API. Со времён JDK 9 в рамках проекта Jigsaw ведётся работа по сокрытию их от публичного использования.

Цель введения строгой инкапсуляции в JDK 16 — миграция ПО с внутренних на стандартные элементы разработки. По умолчанию запрещается доступ к пакетам, не содержащим критических внутренних API. Будьте внимательны при переходе на новую версию! Некоторые библиотеки (например, Lombok) оказались не готовы к таким изменениям, даже спустя четыре года после начала инкапсуляции.

Что делать, если ваше ПО зависит от API из списка внутренних пакетов, к которым по умолчанию будет отказано в доступе?

  1. Перепишите приложение, не ссылаясь на эти элементы;
  2. Временно используйте специальные ключи –illegal-access. Процесс работы с ними приведен в описании JEP.

Отказ от использования внутренних элементов Java в пользовательском ПО повысит безопасность платформы — всех имплементаций Java SE в целом и JDK в частности.

Собственный функционал Axiom JDK

Мы всегда стремимся предлагать своим клиентам особенный опыт использования Liberica JDK — и этот масштабный релиз не исключение.

  • Discovery API v1 остается текущей стабильной версией. Все новые бинарные файлы Axiom JDK доступны по тому же API.
  • Контейнеры по умолчанию в Spring Boot. Преимущество, доступное всем еще до релиза: при сборке стандартного Docker-контейнера на фреймворке Spring с плагином Maven в качестве базового образа автоматически выбирается Axiom JDK.
  • Поддержка AOT и Graal JIT. В сборках Oracle OpenJDK 16 эти экспериментальные функции признаны устаревшими. Мы — сторонники технологии Native Image и рекомендуем использовать Axiom NIK для безошибочной компиляции нативных образов.

С каждым новым релизом комьюнити OpenJDK работает всё слаженнее и тонко реагирует на пожелания разработчиков. Вместе мы создаем код, повышающий производительность ПО по всему миру. И не за горами сентябрь, который принесет нам JDK 17 — первую за три года LTS-версию Java Development Kit.

Готовые сборки Liberica JDK 16 уже доступны на странице версии или по кнопке ниже.

Author image

Олег Чирухин

Директор по коммуникациям с разработчиками (DevRel)

Команда Axiom JDK roman.karpov@axiomjdk.ru Команда Axiom JDK logo Axiom Committed to Freedom 199 Obvodnogo Kanala Emb. 190020 St. Petersburg RU +7 812-336-35-67 Команда Axiom JDK 199 Obvodnogo Kanala Emb. 190020 St. Petersburg RU +7 812-336-35-67