Много интересных фич
Выход Java 18 назначен на 22 марта 2022 года, ждать осталось недолго. Релиз уже несколько дней находится во второй фазе стабилизации, а значит, список фич уже финализирован, а значит настало время обратить на них наше внимание.
Важно понимать, что версии, которые выходят между LTS-релизами, в частности помогают опробовать новые возможности и посмотреть, зайдут ли они комьюнити. Бизнесы, если решат обновляться, будут чаще всего ждать полноценной многолетней поддержки. Поэтому в 18-й версии будет несколько JEP в виде превью и инкубаторов, которые разработчики будут тестировать и давать обратную связь. И уже в готовом виде эти улучшения войдут в 22-ю версию Java.
Сейчас у нас есть возможность попробовать новый функционал и понять, насколько он полезен. А пробовать есть что!
В этой статье мы рассмотрим новые JEP и объясним, что они делают, и для чего они нужны.
Новые фичи в Java 18
JEP 400: Использование UTF-8 по умолчанию
Что это такое: Многие API (включая стандартные Java API) используют в приложениях так называемый “набор символов по умолчанию”. Какой именно 一 зависит от платформы, будь это Windows, Linux, Mac и другие ОС. Более того, та же кодировка использовалась для сохранения исходных .java файлов .
С 18-й Java по умолчанию всегда используется UTF-8.
Зачем это нужно: В некоторых случаях (особенно, когда это касалось азиатских языков и иероглифов), одно и то же приложение, запущенное разными пользователями (даже на одной машине), могло привести к искажению текста. Если виртуальная машина считает кодировкой “по умолчанию” UTF-8, а программа написана в, например, UTF-16, то это может превратить выдаваемый текст в абракадабру, или даже повлиять на работу компилятора javac.
Об этом, кстати, стоит помнить при миграции с ранних версий Java™, которая, возможно, потребует перекодировки исходных файлов.
Но начиная с 18-й версии эта проблема исчезнет. А при необходимости всегда есть возможность установить другую кодировку по умолчанию вручную.
JEP 408: Простой Web Server
Что это такое: В Java появится легковесный веб-сервер, который можно будет запустить с помощью простой команды $ jwebserver
Зачем это нужно: Для тестирования, прототипирования и обучения. Встроенный сервер, конечно, не предназначен для замены промышленных веб-серверов в конечном продукте. Зато теперь нет необходимости в их настройке только для того, чтобы проверить, работает ли бизнес-логика. Можно программно создавать новые и кастомизировать имеющиеся обработчики адресов.
JEP 413: Кусочки кода в документации Java API
Что это такое: Добавляется новый тег @snippet, который используется в комментариях к коду. Если пометить им часть комментария, то компилятор будет валидировать его и оформлять как если бы это был реальный код.
Зачем это нужно: Для вашего удобства! Код в комментариях может содержать кучу ошибок, связанных с человеческим фактором 一 в первую очередь, опечатками. Конечно, компилятор не сможет превратить плохой код в хороший, но про отсутствующую скобку напомнит. А хорошие читаемые комментарии могут сэкономить часы работы при анализе чужого, да и своего кода.
JEP 416: Новая реализация Core Reflection через MethodHandle
Что это такое: Механизм рефлексии переписан поверх MethodHandle-ов, которые заменяют генерацию байткода для Method::invoke, Constructor::newInstance, Field::get и Field::set.
Зачем это нужно: Для безопасности и скорости, а также разработки project Valhalla. До этого использовалось три механизма java.lang.reflect API: нативные методы виртуальной машины, динамически генерируемые байткод-стабы в сочетании с доступом к полям через Unsafe, и, собственно, method handles. Такое разнообразие сложно поддерживать при добавлении новых фич, таких как примитивные классы и дженерики с поддержкой примитивов.
Теперь механизм с использованием нативных методов используется только на раннем этапе запуска виртуальной машины. Для улучшения производительности рефлексии в горячем коде рекомендуется хранение экземпляров Method, Constructor и Field в static final полях, чтобы JIT оптимизировал их как константы.
JEP 417: Vector API (третий инкубатор)
Что это такое: Vector API, представленный в Java 16, помогает существенно повысить производительность приложений в некоторых случаях. Он позволяет вручную писать платформенно-независимые векторные алгоритмы на Java™, когда существующая автоматическая векторизация циклов HotSpot не срабатывает для сложного кода.
Зачем это нужно: Производительность некоторых вычислений в области, например, финансовых операций, машинного обучения и криптографии. Эта версия API 一 в стадии третьего инкубатора, созданного на основе отзывов сообщества. Она содержит новые функции, включая поддержку инструкций ARM Scalable Vector Extension (SVE) и повышенную эффективность векторных операций, принимающих маски на архитектурах, аппаратно поддерживающих маскирование.
JEP 418: Интерфейс сервис-провайдера для разрешения сетевого адреса
Что это такое: Сейчас для разрешения имен хостов в межсетевом протоколе (IP), в Java™ используется API java.net.InetAddress. Он, в свою очередь, использует механизм разрешения адреса через системный вызов ОС. Обычно он работает с файлом hosts в сочетании с DNS (система доменных имен).
Этот JEP внедряет интерфейс поставщика услуг (SPI) и ряд новых классов, чтобы API java.net.InetAddress мог использовать другие механизмы разрешения адреса.
Зачем это нужно: Для тестирования, кастомизации и реализации DNS на клиенте без удержания потока операционной системы. Это позволяет, например, эффективно использовать проект Loom, в котором обработка сетевых запросов не будет препятствовать одновременной работе множества виртуальных потоков.
JEP 419: Foreign Function & Memory API (второй инкубатор)
Что это такое: Улучшение фичи, внедренной в более раннюю версию для замены Java Native Interface (JNI) на более продвинутую модель разработки с использованием чисто Java™ кода. Данный JEP позволит подключать нативные библиотеки, вызвать внешние функции и получать более эффективный доступ к памяти за пределами кучи.
В режиме второй инкубации были добавлены новые носители (carriers), такие как boolean и MemoryAddress, упрощенные API для получения downcall MethodHandle-ов (Java→native) и для управления временными зависимостями областей видимости ресурсов. Представлен обобщенный API разыменования для MemorySegment и MemoryAddress.
Зачем это нужно: Для легкого взаимодействия с библиотеками, написанными на других языках. Становится возможным использовать при таком взаимодействии современные идиомы Java, например параллельные стримы при переносе данных.
JEP 420: Pattern Matching для switch (второй preview)
Что это такое: Еще одно обновление уже имеющейся фичи, которая позволяет проверять выражения на соответствие различным образцам с определенным действием для каждого из них. Ранее эта фича была представлена в режиме preview, а сейчас в нее внесены два улучшения.
Первое заключается в том, что проверка доминирования требует, чтобы константная метка оператора case стояла всегда перед защищенным (guarded) образцом того же типа. Благодаря этому селектор-выражение может соответствовать нескольким меткам в блоке switch. Кроме того, может использоваться любой ссылочный тип. Взгляните на этот пример:
static void error(Object o) {
switch(o) {
case CharSequence cs ->
System.out.println("A sequence of length " + cs.length());
case String s -> // Error - pattern is dominated by previous pattern
System.out.println("A string: " + s);
}
}
Если метка в блоке switch будет перекрываться меткой, поставленной ранее в данном блоке, это приведет к ошибке во время компиляции. Таким образом, в похожих ситуациях вы можете обнаружить плохо написанный код. Второе улучшение заключается в повышении эффективности проверки блоков switch на предмет полноты. В результате проверка будет более точной в запечатанных (sealed) иерархиях, где разрешенный непосредственный наследник лишь расширяет вариант обобщенного (generic) родительского класса с осуществленной подстановкой типов. Другими словами, компилятор не только помогает поддерживать код в упорядоченном состоянии, но и полностью понимает иерархии sealed классов.
Зачем это нужно: Как и прошлый JEP, этот сделает Java более современной. Старый синтаксис, разработанный 20 лет назад, проигрывает по удобству написания кода в сравнении с новыми языками программирования, и разработчики Java устраняют этот разрыв подобными нововведениями.
JEP 421: Объявление функции финализации устаревшей
Что это такое: Скрывается устаревшая функция финализации, которая была представлена еще в Java 1.0. В дальнейшем она будет полностью удалена.
Зачем это нужно: Финализация применялась для устранения проблем утечки внешних ресурсов, больше не используемых приложением.
Автоматическая система управления памятью должна применять сборщик мусора для того, чтобы находить недоступные объекты и освобождать их память.
На практике при работе с объектами, которые работают с ресурсами не только виртуальной машины, но и скажем операционной системы, (например, файловыми дескрипторами или блоками нативной памяти), возникает следующая проблема: при освобождении объекта связанные с ним ресурсы операционной системы не освобождаются автоматически (нужен дополнительный вызов).
Результатом становится утечка ресурса, который операционная система продолжает считать используемым.
Для борьбы с этим явлением сначала использовался явный вызов Java-методов, освобождающих внешние ресурсы объектов. Его недостаток - высокая вероятность ошибок. К тому же момент вызова может быть выбран не оптимально.
Следующим решением стала финализация, целью которой было снять с разработчика задачу гарантированного высвобождения ресурсов. Финализаторы вызываются сборщиком мусора автоматически и гарантированно освобождают ресурсы, относящиеся к неиспользуемым объектам.
На практике финализация столкнулась со множеством проблем в работе.
Время между моментом, когда объект становится недоступным, и вызовом финализатора, могло быть длительным. Весь этот период ресурсы, которые использовал объект, остаются захваченными.
Финализатор может сохранять ссылку на финализируемый объект, а это в свою очередь делает возможным его “воскрешение”.
Финализатор выполняется всегда, даже когда его работа не требуется, например, при закрытии программы.
Для работы финализаторов используются неконтролируемые потоки, и порядок выполнения финализаторов также не определен.
В результате финализаторы создавали новые проблемы безопасности, замедляли или останавливали работу программы, ненадежно исполнялись и усложняли программирование. Например, ресурсы могли освобождаться медленнее, чем захватывались, что всё равно приводило к их утечке.
Именно поэтому были разработаны альтернативные инструменты, такие как cleaner-ы с явной регистрацией объектов и интерфейс AutoCloseable в сочетании с оператором try-with-resources.
Процесс перехода займет немало времени, так как многие нативные библиотеки и сам JDK используют финализаторы, которые необходимо убрать из кода.
Java 18, есть ли повод обновить рантайм?
Java 一 зрелый язык, но подобные нововведения обновляют ее достаточно, чтобы составить конкуренцию по удобству и функциональности более молодым языкам программирования, сохранив все богатство возможностей, мультиплатформенность и обратную совместимость.
Стоят ли они того, чтобы обновить свой рантайм до не-LTS версии? В большинстве случаев 一 нет. Но учитывая новый полугодовой цикл выпуска новых версий и скорое окончание поддержки Java 8, на которой до сих пор работает множество приложений, оно помогает смотреть в будущее с оптимизмом. Выход новой LTS-версии станет большим событием, а разработку новых программ имеет смысл начинать уже на 18-й Java, поскольку апгрейд с нее будет простым и удобным.
Комментарии (29)
Enokin
08.02.2022 10:30+8Лет через 10, поюзаем в продакшн
tbl
08.02.2022 17:21+2Угу, где-то да. До сих пор рекрутеры в личку стучатся с предложениями: "Ищу Java-разработчика в один из крупнейших российских банков. Java 8, 11, настоящий High-load и Микросервисы! Актуальный стек: Struts, Hibernate, Tomcat, ActiveMQ, Maven, ... "
mrbald
09.02.2022 00:46Буквально месяц назад апгрейдился, долго думал, выбрал Java 11, она последний LTS на который более-менее переползла экосистема, запускать 6-месячные релизы в prod не круто. Так что нормально, что ищут Java 11. ActiveMQ если правильно настроить (особенно Artemis) тоже вполне себе middleware, пашет и есть не просит.
tbl
09.02.2022 02:53+1Java 17 - LTS, уже три патча вышли, скоро следующая мажорная версия выходит, большая часть экосистемных библиотек уже переползли на нее (из того, что используем - spring (boot, webflux, micrometer, spring-data-jdbc), netty, reactor, jackson, guava, log4j2, retrofit, grpc, junit, драйверы к очередям и бд (в том числе и jdbc)). Мы у себя инфраструктурные проекты уже на 17 перевели. Теперь потихоньку внешние сервисы мигрируем с java 11 (слава богу, нет Java EE с легаси-зависимостями)
Teapot Автор
09.02.2022 11:14+1Более того, в следующем году уже и очередной LTS релиз выйдет (JDK 21). Актуальный Spring конечно - это сильный довод в пользу 17.
11 в данный момент тоже хорошо, так как до последнего врмемени портировались в заметных количествах улучшения (в отличие от 8), и как раз перестают, ну и стабилизация тоже активная. То есть в каком-то смысле сейчас самый пик поддержки 11.
tbl
08.02.2022 10:37В switch-выражениях теперь вымораживает возможность указать
default ->
иcase default ->
, что выглядит одинаково, но второй является уже вариантом для паттерн-матчинга (позволяя, например, комбинировать так:case default, null ->
). Надеюсь, первый вариант синтаксиса задеприкейтят и удалят в будущих версиях в пользу второго.BugM
08.02.2022 23:37Удалить нельзя ничего. По крайней мере быстрее чем лет за 30 точно.
new Date() передает привет.
tbl
08.02.2022 23:47+1Это синтаксический сахар языка, а не библиотека или байт-код. Совместимость на уровне скопированного кода не нарушится. Просто старые java-файлы перестанут компилироваться без внесения изменений. Это некритично для сохранения обратной совместимости. Уже делали более сильные изменения.
BugM
08.02.2022 23:52Просто старые java-файлы перестанут компилироваться без внесения изменений. Уже делали более сильные изменения.
Можно пример? Чтобы java код написанный без библиотек перестал компилироваться.
tbl
09.02.2022 02:37+1Из того, что помню: добавление ключевых слов assert в 1.4 (сломался junit и код, который его использует), enum в 1.5, запрет на использование символа подчеркивания в качестве идентификатора переменной в java 11. К каждой версии JDK выпускается Migration guide, в котором описываются несовместимые изменения в jls, jvms, рантайм-библиотеке и тулзах, поставляемых с jdk(jre)
BugM
09.02.2022 03:06+2добавление ключевых слов assert в 1.4 (сломался junit и код, который его использует
Библиотеки ломаются время от времени. Я именно про core java.
enum в 1.5
Спецификации уже нет. Увы. Таких исторических книжек у меня тоже уже нет.
https://docs.oracle.com/javase/specs/index.html
запрет на использование символа подчеркивания в качестве идентификатора переменной в java 11
An identifier is an unlimited-length sequence of Java letters and Java digits, the first of which must be a Java letter.
The "Java letters" include uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons, the ASCII dollar sign ($, or \u0024) and underscore (_, or \u005f). The dollar sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems. The underscore may be used in identifiers formed of two or more characters, but it cannot be used as a one-character identifier due to being a keyword.https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.8
Для сравнения 6 https://docs.oracle.com/javase/specs/jls/se6/html/lexical.html#3.8
К каждой версии JDK выпускается Migration guide, в котором описываются несовместимые изменения в jls, jvms, рантайм-библиотеке и тулзах, поставляемых с jdk(jre)
Конечно. Но чтобы ломались базовые языковые фичи языка это вам не к Джаве. Тем более после истории третьего Питона. Все теперь совсем умными стали.
tbl
09.02.2022 03:26+1То, что вы в ссылках привели, как раз и подтверждает, что язык меняется от версии к версии: добавляются новые ключевые слова, которые нельзя использовать в идентификаторах в java-коде. Некоторые слова наоборот убирают, например, ставший ненужным strictfp (если попытаться скомпилировать код с ним, то, начиная с 17 версии jdk, компиляция будет падать)
BugM
09.02.2022 14:23strictfp это отличный пример. Он лет 10 вроде уже ничего не делал? И только сейчас выпилили.
Удаление фич с ломанием обратной совместимости это тяжёлый и долгий путь. Ломать семантику switch это история минимум лет на 20. Вероятнее что даже начинать не будут.
tbl
09.02.2022 14:55+1Switch-expression (
case blablabla ->
) в java 12 добавили (релиз был в 2019 году). Я не имею ввиду switch-statement (case blablabla:
). Последнее трогать не предлагаю.BugM
09.02.2022 16:20+1Когда добавили это не важно. Оно попало в LTS релиз. На этом все. Это навсегда или почти навсегда. Быстрее 20 лет точно ничего никто не удалит.
Myxach
JEP 413: Кусочки кода в документации Java API
JEP 419: Foreign Function & Memory API (второй инкубатор)
JEP 420: Pattern Matching для switch (второй preview)
Вроде все, что интересно. Может кому-то ещё рефлексия зайдет.
olegchir
Хей @tagir_valeev а в Идее @сниппеты можно автодополнять? Можно сделать какой-нибудь рефакторинг типа "move to snippet"?
Teapot Автор
Тогда уж и запуск сниппета!
Myxach
и это все при исполнение программы