После шести месяцев разработки компания Oracle выпустила платформу Java SE 16 (Java Platform, Standard Edition 16), в качестве эталонной реализации которой используется открытый проект OpenJDK. В Java SE 16 сохранена обратная совместимость с прошлыми выпусками платформы Java, все ранее написанные Java-проекты без изменений будут работоспособны при запуске под управлением новой версии. Готовые для установки сборки Java SE 16 (JDK, JRE и Server JRE) подготовлены для Linux (x86_64, AArch64), Windows и macOS. Разработанная в рамках проекта OpenJDK эталонная реализация Java 16 полностью открыта под лицензией GPLv2 с исключениями GNU ClassPath, разрешающими динамическое связывание с коммерческими продуктами.
Java SE 16 отнесён к категории выпусков с обычным сроком поддержки, обновления для которого будут выпускаться до следующего релиза. В качестве ветки с длительным сроком поддержки (LTS) следует использовать Java SE 11, обновления для которого будут выпускаться до 2026 года. Следующий LTS-релиз намечен на сентябрь 2021 года. Напомним, что начиная с выпуска Java 10 проект перешёл на новый процесс разработки, подразумевающий более короткий цикл формирования новых релизов. Новая функциональность теперь развивается в одной постоянно обновляемой master-ветке, в которую включаются уже готовые изменения и от которой раз в шесть месяцев ответвляются ветки для стабилизации новых выпусков.
При подготовке нового выпуска разработка переведена с системы управления версиями Mercurial на Git и платформу совместной разработки GitHub. Ожидается, что миграция позволит повысить производительность операций с репозиторием, увеличить эффективность хранения, обеспечить доступ к изменениям за всю историю проекта, улучшить поддержку рецензирования кода и задействовать API для автоматизации рабочих процессов. Кроме того, применение Git и GitHub делает проект более привлекательным для новичков и разработчиков, привыкших к Git.
Из новшеств Java 16 можно отметить:
- Добавлен экспериментальный модуль jdk.incubator.vector с реализацией API Vector, предоставляющего функции для векторных вычислений, которые выполняются с использованием векторных инструкций процессоров x86_64 и AArch64 и позволяют одновременно применить операции сразу к нескольким значениям (SIMD). В отличие от предоставляемых в JIT-компиляторе HotSpot возможностей по автовекторизации скалярных операций, новый API позволяет явно управлять векторизацией для параллельной обработки данных.
- В коде JDK и VM HotSpot, написанном на C++, разрешено использовать возможности, появившиеся в спецификации C++14. Ранее допускалось использование стандартов C++98/03.
- В сборщик мусора ZGC (Z Garbage Collector), работающий в пассивном режиме и насколько это возможно минимизирущий задержки из-за сборки мусора, добавлена возможность параллельной обработки стеков потоков без приостановки выполнения потоков приложения. В ZGC теперь остались только требующие приостановки работы, которые имеют постоянные задержки, обычно не превышающие нескольких сотен микросекунд.
- В классах SocketChannel, ServerSocketChannel и java.nio.channels добавлена поддержка Unix-сокетов (AF_UNIX).
- Реализован порт для Linux-дистрибутива Alpine cо стандартной Си-библиотекой musl, который популярен в окружениях для контейнеров, микросервисов, облачных и встраиваемых систем. Предложенный порт в подобных окружениях позволяет выполнять программы на Java как обычные приложения. Кроме того, при помощи jlink можно убрать все неиспользуемые модули и сформировать минимальное окружение, достаточное для выполнения приложения, что позволяет создавать специфичные для конкретных приложений компактные образы.
- Реализован механизм Elastic Metaspace, оптимизирующий операции выделения и возвращения памяти, занимаемой метаданными классов (metaspace) в JVM HotSpot. Применение Elastic Metaspace снижает фрагментацию памяти, уменьшает накладные расходы в загрузчике классов, а также благотворно влияет на производительность длительно выполняемых серверных приложений за счёт более быстрого возврата операционной системе памяти, занимаемой неиспользуемыми метаданными классов. Для выбора режима высвобождения памяти после выгрузки классов предложена опция “-XX:MetaspaceReclaimPolicy=(balanced|aggressive|none)”.
- Добавлен порт JDK для систем Windows, работающих на оборудовании с процессорами на базе архитектуры AArch64.
- Предложен третий предварительный вариант API Foreign-Memory Access, позволяющий Java-приложениям безопасно и эффективно получить доступ к областям памяти, вне кучи Java, манипулируя новыми абстракциями MemorySegment, MemoryAddress и MemoryLayout.
- Реализован экспериментальный API Foreign Linker, предоставляющий доступ из Java к нативному коду. Вместе с API Foreign-Memory новый программный интерфейс заметно упрощает создание обвязок над обычными разделяемыми библиотеками.
- Добавлена утилита jpackage, позволяющая создавать пакеты для самодостаточных (self-contained) Java-приложений. Утилита базируется на javapackager из JavaFX и позволяет формировать пакеты в форматах, родных для различных платформ (msi и exe для Windows, pkg и dmg для macOS, deb и rpm для Linux). Пакеты включают все необходимые зависимости.
- Включена по умолчанию строгая инкапсуляция всех внутренних элементов JDK, за исключением критических API, таких как sun.misc.Unsafe. Значение опции “–illegal-access” теперь по умолчанию выставлено в “deny” вместо “permit”, что приведёт к блокированию попыток обращения из кода к большинству внутренних классов, методов и полей. Для обхода ограничения следует использовать опцию “–illegal-access=permit”.
- Стабилизирована реализация сопоставления c образцом в операторе “instanceof”, которая позволяет сразу определить локальную переменную для обращения к проверенному значению. Например, можно сразу писать “if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..}” без явного определения “String s = (String) obj”.
Было: if (obj instanceof Group) { Group group = (Group) obj; var entries = group.getEntries(); }
Теперь можно обойтись без определения “Group group = (Group) obj”: if (obj instanceof Group group) { var entries = group.getEntries(); } - Стабилизирована реализация ключевого слова “record“, предоставляющего компактную форму для определения классов, позволяющую обойтись без явного определения различных низкоуровневых методов, таких как equals(), hashCode() и toString(), в случаях, когда данные сохраняются только в полях, поведение работы с которыми не меняется. Когда в классе используются типовые реализации методов equals(), hashCode() и toString(), в нём можно обойтись без их явного определения: public record BankTransaction(LocalDate date, double amount, String description) {}
Данное объявление приведёт к автоматическому добавлению реализаций методов equals(), hashCode() и toString() в дополнение к конструктору и методам, контролирующим изменение данных (getter).
- Предложен второй предварительный вариант запечатанных (“sealed”) классов и интерфейсов, которые не могут использоваться другими классами и интерфейсами для наследования, расширения или переопределения реализации. Запечатанные классы также предоставляют более декларативный способ ограничения использования суперкласса, чем модификаторы доступа, основанный на явном перечислении подклассов, разрешённых для расширения. package com.example.geometry; public sealed class Shape permits com.example.polar.Circle, com.example.quad.Rectangle, com.example.quad.simple.Square {…}