Перейти к содержимому

Jdk 16 что нового

  • автор:

Что нового в Java 16 и как на это отреагировали разработчики

С помощью экспертов разобрались, что нового и интересного появилось в Java 16, а также собрали мнения разработчиков из соцсетей.

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

Артём Первушин
IT-директор Extyl

Пользователи соцсетей тоже активно обсуждают нововведения в Java 16, но пока это чисто теоретический интерес. На Reddit под новостью о релизе Java 16 даже устроили небольшую перепись, кто какой версией пользуется.

Многие пишут на Java 8, но есть и те, кто до сих пор использует Java 7, Java 6 и Java 5. В некоторых компаниях недавно завершили миграцию с Java 8 на Java 11, есть и те, кто только начинает этот процесс.

Подписчики нашего новостного канала в Telegram тоже обсудили, с какими версиями Java им приходится работать.

Какие возможности Java 16 выделяют разработчики

Полный список нововведений можно посмотреть на странице релиза. Здесь же собраны только те возможности, которые вызвали у разработчиков наибольший интерес.

  • Pattern Matching — оператор instanceof с паттерн-матчингом теперь стал стабильной синтаксической конструкцией и больше не требует флага —enable-preview .
  • Stream.toList() — метод собирает содержимое Stream в неизменяемый список и возвращает его.
  • Stream.mapMulti() — императивный аналог Stream.flatMap(), принимающий процедуру с двумя параметрами, где первый параметр – текущий элемент, а второй – Consumer, в который кладутся значения.
  • Records — записи обеспечивают компактный синтаксис для объявления классов, позволяющий в некоторых случаях обойтись без явного определения низкоуровневых методов вроде equals(), hashCode() и toString().

Роман Иванов
Java-разработчик
Юрий Авраменко
Senior Software Developer

Пользователи соцсетей тоже оценили добавление метода Stream.toList() и уже планируют применять его в своих проектах.
Card

Lombok по умолчанию не работает на Java 16. Есть патч, но к нему много вопросов

Библиотека Lombok несовместима с JDK 16. Чтобы обойти ограничение, разработчики использовали разные хаки — например, прописывали кучу флагов —add-opens в конфигурации. Но после релиза Java 16 появился патч, который устраняет этот недостаток. Однако к его реализации есть вопросы. Вот большой разбор с указанием возможных негативных последствий. Если кратко — в любой момент Lombok может сломаться.


Однако не все разработчики считают несовместимость с Lombok серьёзной проблемой. Есть мнение, что Records покроет большую часть потребностей в использовании библиотеки.

В любом случае, возможности Java 16 показывают разработчикам, чего следует ожидать от следующей версии с длительной поддержкой. Релиз Java 17 LTS запланирован на сентябрь 2021 года.

Вышла Java 16

Вышла 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 >>

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 >); // Возвращает 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

JDK 16: Что нового принесет Java 16

В Java Development Kit (JDK) 16 в конце октября были добавлены еще две предлагаемые новые функции, API доступа к внешней памяти и сопоставления с образцом (прим.пер. Pattern Matching). Ранее предложенные функции включают в себя готовый к производству инструмент для упаковки приложений, thread-stack процессинг при сборке мусора, поддержку функций языка C++ 14 и возможность “эластичного metaspace” для более быстрого возврата неиспользуемой памяти для метаданных классов в ОС.

JDK 16 будет эталонной реализацией версии стандартного набора Java, следующей за JDK 15, вышедшим 15 сентября. График выпуска JDK 16 предполагает стадии рампдаунов(пре-релизов) 10 декабря и 14 января 2021 года, а затем 4 февраля и 18 февраля 2021 года выпускаются релиз-кандидаты. Промышленный релиз намечен на 16 марта 2021 года.

По состоянию на 4 ноября 2020 года в JDK 16 официально предполагается внедрить тринадцать предложений. Новые возможности Java 16 включают:

  • Перемещение thread-stack процессинга ZGC (Z Garbage Collector) из безопасных точек (safepoints) в параллельную фазу. Планируется: удаление thread-stack процессинга из безопасных точек ZGC; теперь thread-stack процессинг станет ленивым, кооперативным, параллельным и инкрементальным; удаление всех других корневых процессов для каждого потока из безопасных точек ZGC; и предоставление механизма для других подсистем виртуальной машины HotSpot для ленивой обработки стеков. ZGCпредназначен для того, чтобы сделать паузы GC и проблемы масштабируемости в HotSpot делом прошлого. До сих пор операции GC, время исполнения которых кореллировало с размером кучи и размером Metaspace, были перемещены из безопасных точек в параллельные фазы. Это такие операции как маркировка, перемещение, обработка ссылок, выгрузка классов и большая часть обработки корневых ссылок. Единственные действия, которые все еще выполняются в безопасных точках GC, — это обработка корневых подмножеств и ограниченная по времени операция завершения маркировки. Эти корневые ссылки размещались в стеках потоков Java и в других корневых ссылках, причем эти корневые ссылки были проблематичными, поскольку они дублировались в каждом потоке. Чтобы выйти из текущей ситуации, обработка каждого потока, включая сканирование стека, должна быть переведена в параллельную фазу. При таком подходе стоимость задержки должна быть незначительной, а время, затрачиваемое на безопасных точках ZGC на типичных машинах, должно составлять менее одной миллисекунды.
  • Возможность эластичного Metaspace, которая быстрее возвращает в ОС неиспользуемую для метаданных память HotSpotVM, сокращает ресурсы, требуемые для Metaspace и упрощает его код, что снижает затраты на обслуживание. У Metaspace были проблемы с высоким использованием памяти вне кучи. Планируется замена существующего менеджера памяти на схему buddy-allocation, которая делит память на блоки, наиболее подходящие под запросы на выделение памяти. Этот подход был использован, среди прочего, в ядре Linux, и позволит выделять память меньшими кусками, чтобы снизить потребности загрузчика классов. Фрагментация также уменьшится. Кроме того, лениво, по мере необходимости, будут выделяться новые блоки памяти за счёт ОС, что позволит уменьшить объем памяти для загрузчиков, требующих при старте большого объёма памяти, но не использующие весь объём сразу или не нуждающиеся в их полном использовании вообще. Чтобы полностью использовать эластичность, предлагаемую buddy-allocation, память Metaspace будет организована в одинаковые по размеру блоки, которые могут выделяться или нет, независимо друг от друга.
  • Включение возможностей языка C++ 14, JDK позволит использовать возможности C++ 14 в исходном коде с конкретными указаниями о том, какие из этих возможностей могут быть использованы для виртуальной машины HotSpot. В соответствии с JDK 15 языковые возможности, используемые кодом C++ в JDK, были ограничены языковыми стандартами C++ 98/03. В JDK 11 исходный код был обновлен для поддержки более поздних стандартов C++. В том числе появилась возможность сборки с последними версиями компиляторов, поддерживающих функции языка C++ 11/14. Это предложение не предлагает изменений стиля или использования кода C++, за пределами HotSpot. Но чтобы воспользоваться преимуществами возможностей языка C++, требуются некоторые изменения во время сборки, в зависимости от компилятора платформы.
  • Векторный API на стадии инкубатора, в котором JDK будет оснащен модулем инкубатора, jdk.incubator.vector для выражения векторных вычислений, которые компилируются в оптимальные аппаратные векторные инструкции на поддерживаемых архитектурах ЦП, и позволят достичь более высокой производительности по сравнению с эквивалентными скалярными вычислениями. Vector API предоставляет механизм для написания сложных векторных алгоритмов на Java, используя уже существующую поддержку в виртуальной машине HotSpot для векторизации, но с пользовательской моделью, которая делает векторизацию более предсказуемой и надежной. Цели этого предложения включают в себя предоставление четкого и ясного API для выражения целого ряда векторных вычислений, будучи платформо-независимым за счёт поддержки нескольких архитектур процессоров, а также предлагая надежную компиляцию во время выполнения и производительность на архитектурах x64 и AArch64. Целью также является отказоустойчивость, когда векторное вычисление будет постепенно деградировать, но продолжать исполняться, если оно не может быть полностью выражено в runtime (во время выполнения) в виде последовательности аппаратных векторных инструкций, либо потому, что архитектура не поддерживает некоторые инструкции, либо не поддерживается архитектура процессора.
  • Перенос JDK на платформу Windows/AArch64. Выпуск нового класса серверов и потребительского оборудования вызвал спрос, сделавший AArch64 (ARM64) Windows/AArch64 важной платформой. Хотя само портирование уже в основном завершено, основное внимание в этом предложении уделяется интеграции порта в магистральный репозиторий JDK.
  • Перенос JDK на AlpineLinux и другие дистрибутивы Linux, использующие musl в качестве основной библиотеки C, на архитектуры x64 и AArch64. Musl-это Linux-реализация функциональности стандартной библиотеки, описанной в стандартах ISOC и Posix. AlpineLinuxшироко распрстранена в облачном развертывании, микрослужбах, и контейнер-среде благодаря небольшому размеру образа. Размер образа Docker для Linux меньше 6 МБ. Готовность Jawa к работе «из коробки» позволит в Tomcat, Jetty, Spring, и другим популярным платформам сразу нативно работать в таких условиях. Используя jlink для уменьшения размера Java runtime, пользователь может создать еще меньший образ, адаптированный для запуска конкретного приложения.
  • Предоставление классов записей (Records), которые действуют как прозрачные носители для неизменяемых данных. Записи можно считать набором данных. Записи были предварительно представлены в JDK 14 и JDK 15. Это является ответом на жалобы на излишнюю многословность Java, и на то, что она содержала слишком много «церемоний». Цели включают в себя разработку объектно-ориентированной конструкции, которая просто агрегирует значения, помогая разработчикам сосредоточиться на моделировании неизменяемых данных, а не на расходящихся вариантах поведения, автоматически реализуя такие методы, как equals и accessors, и соответствует давнему принципу Java — строгой типизации.
  • Добавление каналов сокетов Unix-domain, в которых поддержка сокетов Unix-domain (AF_UNIX) добавляется к API-интерфейсам socketchannel и serversocketchannel в пакете nio.channels. План также расширяет механизм наследования для поддержки каналов сокетов Unix-домена и каналов сокетов сервера. Unix-сокеты используются для межпроцессного взаимодействия на одном узле. Они во многих отношениях похожи на сокеты TCP/IP, за исключением того, что адресация происходит именами путей файловой системы, а не IP-адресами и номерами портов. Цель новой возможности-поддержка всех функций Unix-доменных каналов сокетов, которые являются общими для основных платформ Unix и Windows. Каналы сокетов Unix-домена будут вести себя так же, как существующие каналы TCP/IP с точки зрения чтения/записи, настройки соединения, приема входящих соединений серверами и мультиплексирования с другими неблокирующими каналами в селекторе. Сокеты Unix-домена являются более безопасными и более эффективными, чем петлевые соединения TCP/IP для локальных межпроцессных коммуникаций.
  • API доступа к внешней памяти, позволяющий Java-программам безопасно обращаться к внешней памяти за пределами кучи Java. Ранее инкубированный как в JDK 14, так и в JDK 15, API доступа к внешней памяти будет повторно инкубирован в JDK 16, с добавлением уточнений. Изменения включая более четкое разделение ролей между интерфейсами MemorySegment и MemoryAddresses . Цели этого предложения включают предоставление единого API для работы с различными видами внешней памяти, включая собственную, постоянную и управляемую память кучи. API не должны подрывать безопасность виртуальной машины Java. Это предложение мотивированно тем, что многие программы Java, такие как Ignite, Memcached и MapDB, обращаются к внешней памяти. Но Java API не предоставляет удовлетворительного решения для доступа к внешней памяти.
  • Сопоставление с образцом для оператора instanceof, который также был предварительно просмотрен как в JDK 14, так и в JDK 15. Он будет доработан в JDK 16. Сопоставление с образцом позволяет более сжато и безопасно выразить общую логику в программе, а именно условное извлечение компонентов из объектов.
  • Предоставление инструмента для упаковки автономных Java-приложений. Введенный в качестве инкубационного инструмента в JDK 14, jpackage оставался в инкубации в JDK 15. С JDK 16 jpackage переходит в производство, поддерживая собственные форматы пакетов, чтобы дать пользователям опыт нормальной установки и позволить задавать параметры времени запуска во время упаковки. Форматы включают msi и exe в Windows, pkg и dmg в MacOS, а также deb и rpm в Linux. Инструмент может быть вызван непосредственно из командной строки или программно. Новый инструмент упаковки решает ситуацию, в которой многие приложения Java должны быть установлены на собственных платформах первоклассным способом, а не помещены на путь класса или путь модуля. Необходим устанавливаемый пакет, подходящий для нативной платформы.
  • Миграция репозиториев исходного кода OpenJDK из Mercurial в Git. Причиной этих изменений являются преимущества в размере метаданных системы контроля версий, а также доступные инструменты и хостинг.
  • Миграция на GitHub, связанная с миграцией Mercurial-to-Git, с репозиториями исходного кода JDK 16, которые будут находиться на популярном сайте код-шэринга. Переход на Git, GitHub и Skara для Mercurial JDK и JDK-sandbox был произведен 5 сентября и остается открытым для участия.

Сборки раннего доступа JDK 16 для Linux, Windows и MacOS можно найти по адресу jdk.java.net. Как и JDK 15, JDK 16 будет краткосрочным релизом, поддерживаемым в течение шести месяцев. JDK 17, ожидаемый в сентябре 2021 года, будет выпуском с долгосрочной поддержкой (LTS), и будет поддерживаться в течение нескольких лет. Текущая версия LTS, JDK 11, была выпущена в сентябре 2018 года.

Что нового в Java 16

Я уже описывал эту возможность в статье про новые фичи в Java 15, а также в статье про новые возможности Java 14. Там они были только в качестве preview. Однако в Java 16 эта возможность стала доступной окончательно:

| Welcome to JShell — Version 16
| For an introduction type : / help intro
jshell > Object str1 = «Hello» ;
str1 == > «Hello»
jshell > if ( str1 instanceof String str2 ) < . . . > String str3 = str2 ; // Переменная str2 типа String

Записи (Records)

Это тоже не что-то новое. В предыдущей версии и в позапредыдущей версии она была в качестве preview. Сейчас же она стала полноправной частью Java:

jshell > record Point ( int x , int y ) < >
| created record Point

Записи автоматически получают приватные переменные для хранения своего состояния, методы hashCode , equals , toString , работающие с переменными состояния, а также методы для получения значения каждой из переменной состояния.

Сами записи неявно final , их переменные состояния тоже final .

Запечатанные классы

Я описывал их в статье про Java 15. Теперь они во втором preview.

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

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