Вышла 16-я версия платформы Java SE. В этот релиз попало около двух с половиной тысяч закрытых задач и 17 JEP'ов. Изменения API можно посмотреть здесь. Release notes здесь.
Уже сейчас доступны для скачивания дистрибутивы Oracle JDK и OpenJDK.
JEP'ы, которые попали в Java 16, мы разобьём на четыре категории: язык, API, JVM и инфраструктура.
Язык
Паттерн-матчинг для оператора instanceof (JEP 375)
Оператор instanceof
с паттерн-матчингом, который
появился в Java 14 и перешёл
во второе preview в Java 15,
теперь стал стабильной синтаксической конструкцией и больше не
требует флага --enable-preview
. Паттерн-матчинг мы
подробно рассматривали в этой статье, и с того момента в
него было внесено два изменения:
Во-первых, переменные паттернов теперь не являются неявно финальными:
if (obj instanceof String s) { s = "Hello"; // OK в Java 16, ошибка в Java 15}
Во-вторых, если тип выражения, известный на этапе компиляции, является подтипом проверяемого типа, то теперь это ошибка компиляции:
String str = ...if (str instanceof String s) { // Oшибка в Java 16, OK в Java 15}
Записи (JEP 395)
Ещё одна синтаксическая конструкция, которая стала стабильной это записи. Она также была в режиме preview в Java 14 и Java 15. Записи мы также подробно рассматривали ранее. В Java 16 было внесено следующее изменение: теперь во внутренних классах разрешено объявлять статические члены:
public class Outer { public class Inner { // OK в Java 16, ошибка в Java 15 static void main(String[] args) { } // OK в Java 16, ошибка в Java 15 record Point(int x, int y) { } }}
sealed
классы (второе
preview) (JEP 397)
Запечатанные классы, которые появились в Java 15 в режиме preview, остаются в этом статусе. Их мы рассматривали в этой статье. Изменения по сравнению с прошлой версией следующие:
- Теперь в спецификации языка Java появилось понятие contextual
keyword взамен старым понятиям restricted keyword и restricted
identifier, и одними из таких contextual keywords стали
sealed
,non-sealed
иpermits
. - Компилятор теперь производит более строгие проверки при
конверсии типов, в иерархиях которых есть
sealed
классы:sealed interface Sealed {}final class Impl implements Sealed { void f(Runnable r) { Sealed s = (Sealed) r; // error: incompatible types }}
- Метод
Class.permittedSubclasses()
переименован вClass.getPermittedSubclasses()
.
JVM
Строгая инкапсуляция внутренностей JDK по умолчанию (JEP 396)
Инкапсуляция внутренних API JDK, которая была введена в Java 9, теперь стала
строгой: если в Java 9-15 значение опции
--illegal-access
было по умолчанию
permit
, то с Java 16 она становится deny
.
Это значит, что рефлективный доступ к защищённым членам классов и
статический доступ к неэкспортированным API (sun.*
,
com.sun.*
, jdk.internal.*
и т.д.) теперь
будет выбрасывать ошибку.
Если код требует доступа к внутренностям JDK во время выполнения, то чтобы он продолжал работать на Java 16, теперь придётся явно указывать одну из трёх опций JVM:
--illegal-access=permit/warn/debug
: открытие всех пакетов JDK--add-opens=module/package=target-module
: открытие одного пакета--add-exports=module/package=target-module
: экспортирование одного пакета (только для статического доступа)
В будущем опция --illegal-access
может быть удалена
окончательно. Начиная с Java 16, при её использовании выдаётся
предупреждение: Option --illegal-access is deprecated and
will be removed in a future release
.
Изменения не касаются критического API в модуле
jdk.unsupported
: классы в пакетах
sun.misc
и sun.reflect
остаются
доступными без флагов.
Warnings for Value-Based Classes (JEP 390)
Классы-обёртки примитивных типов (Integer
,
Double
, Character
и т.д.) теперь
относятся к категории value-based классов, и их конструкторы,
которые ранее стали deprecated в Java 9,
теперь помечены как deprecated for removal.
Понятие value-based классов появилось в спецификации API
Java 8. Такие классы
являются неизменяемыми, создаются только через фабрики, и в их
использовании не должны использоваться операции, чувствительные к
identity: сравнение на ==
, синхронизация,
identityHashCode()
и т.д. Value-based классы являются
кандидатами для миграции на примитивные классы в рамках
проекта Valhalla, который сейчас
находится в стадии активной разработки.
При синхронизации на объектах value-based классов теперь будет выдаваться предупреждение во время компиляции:
Double d = 0.0;synchronized (d) { // warning: [synchronization] attempt to synchronize on an instance of a value-based class}
Также можно включить проверки синхронизации на value-based объектах во время выполнения с помощью флагов JVM:
-XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1
: при попытке синхронизации будет фатальная ошибка.-XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=2
: при попытке синхронизации будет предупреждение.
ZGC: Concurrent Thread-Stack Processing (JEP 376)
Обработка стеков потоков в сборщике мусора ZGC теперь перенесена из safepoints в конкурентную фазу. Это позволило ещё сильнее уменьшить паузы сборщика мусора.
Unix-Domain Socket Channels (JEP 380)
Добавлена поддержка сокетов доменов Unix в socket channel и server-socket channel API. Такие сокеты используются для межпроцессного взаимодействия внутри одного хоста, и в них не используются сетевые соединения, что делает такое взаимодействие более безопасным и эффективным. Сокеты доменов Unix с недавних пор поддерживаются в Windows 10 и Windows Server 2019.
Elastic Metaspace (JEP 387)
Metaspace (пространство JVM, в котором хранятся метаданные классов) переработан для более эффективной отдачи неиспользуемой памяти обратно операционной системе и меньшего потребления памяти вне кучи в целом. Такое улучшение может быть полезно для приложений, которые интенсивно загружают и выгражают классы посредством большого количества загрузчиков классов.
Alpine Linux Port (JEP 386)
JDK теперь портирован на Alpine Linux и другие дистрибутивы Linux, которые используют musl в качестве реализации стандартной библиотеки C. Alpine Linux популярен в облаках, микросервисах и контейнерах благодаря своему маленькому размеру образа. Новый порт позволит нативно запускать JDK в этих окружениях.
Windows/AArch64 Port (JEP 388)
JDK также портирован на архитектуру Windows/AArch64. Это позволит запускать Java на компьютерах с Windows on ARM, которые в последнее время набирают популярность.
API
Новые методы в Stream
Хотя для этих двух новых методов в интерфейсе
java.util.stream.Stream
нет отдельного JEP, хочется
упомянуть их здесь, так как это довольно заметное изменение.
Первый метод это Stream.toList()
.
Этот метод собирает содержимое Stream
в неизменяемый
список и возвращает его. При этом, в отличие от Collectors.toUnmodifiableList()
,
список, который возвращается из Stream.toList()
,
толерантен к null
-элементам.
Второй метод это Stream.mapMulti()
(и примитивные специализации). Это метод является императивным
аналогом метода Stream.flatMap()
:
если flatMap()
принимает функцию, которая для каждого
элемента должна вернуть Stream
, то
mapMulti()
принимает процедуру с двумя параметрами,
где первый параметр это текущий элемент, а второй Consumer, в
который кладутся значения. Пример:
IntStream.rangeClosed(1, 10).mapMulti((i, consumer) -> { for (int j = 1; j <= i; j++) { consumer.accept(j); }}); // Возвращает 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, ...
Инструмент упаковки (JEP 392)
Инструмент создания самодостаточных приложений
jpackage
, который появился в Java 14 в
инкубационном статусе, теперь стал постоянным модулем.
Vector API (Incubator) (JEP 338)
Появился новый инструментарий для преобразования векторных вычислений в SIMD-инструкции процессора (x64 и AArch64). Векторное API позволит разработчику контролировать процесс компиляции и не полагаться на автовекторизацию, которая в JVM является ограниченным и хрупким механизмом. Явная векторизация может применяться в таких областях как машинное обучение, линейная алгебра, криптография и др.
API находится в инкубационном модуле jdk.incubator.vector
.
Foreign Linker API (Incubator) (JEP 389)
Ещё одно новое API, которое появилось в результате работы над проектом Panama это Foreign Linker API. Это инструментарий для статического доступа к нативному коду из Java, созданный для замены JNI: он должен быть более простым в использовании, более безопасным и желательно более быстрым.
Про Foreign API делал доклад Владимир Иванов из Oracle.
Foreign-Memory Access API (Third Incubator) (JEP 393)
API для доступа вне кучи Java, которое появилось в Java 14, остаётся в инкубационном статусе с некоторыми изменениями.
Инфраструктура
Enable C++14 Language Features (JEP 347)
Кодовая база JDK до Java 16 использовала стандарты C++98/03. При этом с Java 11 код стал собираться версией с более новым стандартом, однако в нём всё ещё нельзя было использовать возможности стандарта C++11/14. Теперь же часть из этих возможностей использовать можно: в гиде по стилю HotSpot определён список возможностей C++11/14, которые можно использовать и которые нельзя.
Migrate from Mercurial to Git (JEP 357) и Migrate to GitHub (JEP 369)
Совершён переход репозиториев JDK на Git и GitHub. Миграция была полностью завершена в сентябре 2020 года, и разработка Java 16 уже полностью велась в новом репозитории.
Переход на GitHub облегчил процесс принятия изменений контрибьюторами. Теперь изменения предлагаются через привычные большинству пользователей пулл-реквесты, и большая часть процесса автоматизирована с помощью команд и ботов. Подробнее про процесс можно прочитать на странице проекта Skara.
Также сейчас обсуждается переход на Git более старых версий JDK: jdk11u и, возможно, jdk8u.
Java 16 является STS-релизом, у которого выйдет только два обновления.
Если вы не хотите пропускать новости о Java, то подписывайтесь на Telegram-канал miniJUG