Вышла общедоступная версия Java 18. В этот релиз попало более 2000 закрытых задач и 9 JEP'ов. Release Notes можно посмотреть здесь. Изменения API можно посмотреть по этой ссылке.
Ссылки на скачивание:
Перечислим JEP'ы, которые попали в Java 18.
Паттерн-матчинг для switch
(Second Preview) (JEP 420)
Паттерн-матчинг для switch
, который появился в Java 17 в режиме preview, остаётся в этом статусе. В этом релизе присутствует два изменения по сравнению с предыдущей версией.
Первое изменение – константные паттерны теперь должны находиться выше, чем паттерны с условиями того же типа. Например, такой код успешно компилируется в Java 17:
switch (value) {
case Integer i && bar() -> {}
case 3 -> {}
case Integer i -> {}
}
Но не компилируется в Java 18:
> javac --enable-preview --release 18 Main.java
Main.java:8: error: this case label is dominated by a preceding case label
case 3 -> {}
^
Чтобы код компилировался на Java 18, нужно переместить константный паттерн выше:
switch (value) {
case 3 -> {}
case Integer i && bar() -> {}
case Integer i -> {}
}
Второе изменение – улучшенная проверка исчерпываемости для дженериков. Например, такой код не компилируется в Java 17, несмотря на то что switch
покрывает все возможные случаи:
sealed interface Foo<T> { }
final class A<T> implements Foo<T> { }r
final class B<T> implements Foo<T> { }
final class C implements Foo<String> { }
static int testGenericSealedExhaustive(Foo<Integer> foo) {
return switch (foo) {
case A<Integer> a -> 1;
case B<Integer> b -> 2;
};
}
javac --enable-preview --release 17 Main.java
Main.java:10: error: the switch expression does not cover all possible input values
return switch (foo) {
^
В Java 18 же такой код успешно компилируется.
Сниппеты кода в документации Java API (JEP 413)
В JavaDoc теперь поддерживается новый тег @snippet
, который указывает на то, что данный участок является примером кода.
Пример сниппета кода:
/**
* A simple program.
* {@snippet :
* public class HelloWorld {
* public static void main(String... args) {
* System.out.println("Hello World!"); // @highlight substring="println"
* }
* }
* }
*/
Сгенерированная документация для него будет выглядеть примерно следующим образом:
public class HelloWorld {
public static void main(String... args) {
System.out.println("Hello World!");
}
}
Тег @snippet
введён в качестве замены существующему методу вставки примеров кода в JavaDoc с помощью блоков <pre>{@code ... }</pre>
, который имеет ряд недостатков:
- Тег
@code
не поддерживает возможность указания языка фрагмента, а значит теряется возможность проверки корректности кода, подсветки синтаксиса и ссылок, поскольку инструменты трактуют все такие фрагменты как простой текст. - Подсветку синтаксиса также нельзя добавить и вручную, поскольку внутренние HTML-теги будут трактоваться как часть фрагмента. Проблему можно решить через использование тега
<pre>...</pre>
(без@code
), но тогда полностью исчезает указание того, что данный фрагмент документации является кодом. - Фрагменты кода часто являются неполными или содержат плейсхолдеры и многоточия. Тег
@code
никак не решает данную проблему. - Индентация строк во фрагменте остаётся такой, как написана в исходном коде.
Новый тег же не только решает все вышеперечисленные проблемы, но и добавляет новые возможности:
- В сниппете можно указать язык фрагмента с помощью атрибута
lang
:{@snippet lang=properties : ... }
. Если язык не указан, то считается, что это Java. Проверка корректности пока ограничена только сбалансированностью фигурных скобок, но инструменты могут реализовать более сложную проверку. - Подсветка отдельных элементов фрагмента может быть сделана с помощью тега
@highlight
, который поддерживает три стиляbold
,italic
иhighlighted
. Все теги указываются в комментариях, поэтому полностью исчезают после генерации. Инструменты также имеют возможность сделать автоматическую подсветку синтаксиса. - Многоточия и неполные фрагменты кода возможны с помощью тега
@replace
. Фрагмент кода до замены плейсхолдеров остаётся синтаксически валидным кодом. - В сниппете можно сделать ссылки с помощью тега
@link
. - Общие отступы строк фрагмента съедаются при генерации документации.
- При генерации HTML-документации стандартным доклетом сниппеты кода лучше выделяются на фоне остальной документации благодаря серому фону. Кроме того, каждый сниппет кода будет сопровождаться кнопкой копирования в буфер обмена.
- Сниппеты кода могут быть внешними и подтягивать код из внешних файлов. Чтобы иметь возможность не включать весь файл в JavaDoc, поддерживаются регионы с помощью тега
@region
. Внешние сниппеты хороши тем, что внешние файлы могут быть предварительно проверены на корректность (например, если файлы Java не будут компилироваться, то и не смогут быть включены в JavaDoc).
UTF-8 по умолчанию (JEP 400)
UTF-8 теперь является кодировкой по умолчанию на всех платформах. Кодировка по умолчанию используется в таких API как java.io
(InputStreamReader
, FileReader
, OutputStreamWriter
, FileWriter
, PrintStream
), java.util
(Formatter
, Scanner
), java.net
(URLEncoder
, URLDecoder
). Кодировка в пакете java.nio.file
осталась неизменной: в нём самого начала UTF-8 было в качестве Charset
по умолчанию.
Если в Java 17 и более ранних версиях кодировка по умолчанию определялась при старте JVM и зависела от разных факторов (операционная система, пользовательская локаль, кодировка операционной системы), то с Java 18 она всегда UTF-8. Если нужно включить старый механизм установки кодировки при старте, то можно использовать опцию -Dfile.encoding=COMPAT
. Кроме того, эту кодировку можно узнать, используя свойство native.encoding
, которое появилось в Java 17.
Чтобы будущий переход на Java 18 был более гладким, рекомендуется стартовать свои приложения на Java 17 или более ранних версиях с опцией -Dfile.encoding=UTF-8
.
Простой веб-сервер (JEP 408)
Появилась новая утилита jwebserver
, которая запускает простой веб-сервер, предоставляющий статический доступ к указанной папке с файлами. По умолчанию используется текущая директория (если не указана опция -d
), а порт равен 8000 (если не указана опция -p
).
Веб-сервер поддерживает только HTTP/1.1, не поддерживает HTTPS и аутентификацию. Его рекомендуется использовать только для целей разработки и тестирования.
Вместе с утилитой jwebserver
также появилось новое API, позволяющее запускать веб-сервер программно. За это отвечают новые классы SimpleFileServer
, HttpHandlers
и Request
в пакете com.sun.net.httpserver
.
Deprecate Finalization for Removal (JEP 421)
Финализация объектов, которая стала deprecated в Java 9, теперь стала deprecated for removal, то есть подлежит окончательному удалению.
Начиная с Java 18, все методы, относящиеся к финализации, помечены аннотацией @Deprecated(forRemoval=true)
. Это Object.finalize()
и его наследники (часть из них удалены полностью), Runtime.runFinalization()
и System.runFinalization()
.
Сама финализация всё ещё работает, однако появилась новая опция --finalization=disabled
, которая её отключает.
В будущих версиях Java работа по дальнейшему отказу от финализации может быть продолжена. Сначала финализацию предлагается отключить по умолчанию с возможностью включения, потом отключить её полностью, и, наконец, удалить весь API финализации.
Reimplement Core Reflection with Method Handles (JEP 416)
Механизм рефлексии в пакете java.lang.reflect
теперь реализован поверх method handles в пакете java.lang.invoke
. В Java 17 и раньше эти два механизма существовали независимо и имели разную внутреннюю реализацию. Такое дублирование усложняет поддержку платформы и внесение в неё новых языковых изменений.
Для разработчика такое изменение не должно иметь видимых последствий (кроме небольших различий в производительности). Однако на всякий случай предоставлен ключ, позволяющий включить старую реализацию: -Djdk.reflect.useDirectMethodHandle=false
. Старая реализация будет полностью удалена в одной из следующих версий Java.
Internet-Address Resolution SPI (JEP 418)
Появилось новое SPI, позволяющее кастомизировать получение IP-адреса по имени хоста (и наоборот). По умолчанию InetAddress
API делает нативный резолвинг, то есть делегированием операционной системе. Если нужен альтернативный механизм резолвинга, то теперь его можно предоставить путём реализации нового провайдера сервиса InetAddressResolverProvider
.
Примеры случаев, когда может понадобиться альтернативный резолвинг:
- Более производительный резолвинг, чем системный.
- Неблокирующий резолвинг.
- Альтернативный протокол DNS (например, DNS over QUIC).
- Тестирование (подмена IP-адресов, моки).
Foreign Function & Memory API (Second Incubator) (JEP 419)
Foreign Function & Memory API, который появился в Java 17 в инкубационном статусе, остаётся в этом статусе в модуле jdk.incubator.foreign
.
В Java 19 это API перестанет быть инкубационным и станет preview API в пакете java.lang.foreign
.
Vector API (Third Incubator) (JEP 417)
Векторное API, которое появилось в Java 16 в инкубационном статусе, осталось в инкубационном статусе в Java 17, продолжает находиться в этом статусе в модуле jdk.incubator.vector
.
Java 18 не является LTS-релизом и будет получать обновления только в течение полугода (до сентября 2022).
Комментарии (17)
GaDzik
22.03.2022 19:04Блин через года три будем каждый год на новый год новую джаву начинать изудчать.)
Sultansoy
23.03.2022 00:09+7Интересно, что даже не смотря на небольшое количество изменений, обязательно находятся люди, недовольные тем, что нужно что-то новое почитать. Так и не нужно, в конце концов можете и дальше на 8-ой писать, а лучше на 6-ой или 5-ой.
Gmugra
23.03.2022 12:21+5Большая проблема на самом деле.
Новый синтаксис - Бог бы с ним (хотя даже про try-with-resources аксакалы по привычке забывают, а это Java 7)Часто, люди упускают что там нового появилось в стандартном API.
В итоге постоянно вижу например Base64 из внешних библиотек,
не знание о существовании Files.readAllBytes/readString или, скажем, о классе Оbjects.
Вот это вот грустно.
Dmitry2019
23.03.2022 07:04+1Постоянные проблемы с AspectJ. Хоть AspectJ 1.9.8 и должен поддерживать, до сих пор не смог запустить проект на JDK17.
SimSonic
23.03.2022 19:26+1Аспекты вполне написаны и работают в спрингбутовом проекте, который сейчас апнут на 17ю джаву. У вас какой-то более сложный кейс использования?
Dmitry2019
23.03.2022 19:50Да. У нас Spring, SpringIntegration, Hibernate, Gradle и всё под Эклипсом. Эклипс глючит, iajc сыпется со странными ошибками, хотя с 16той работает
VovkaSOL
24.03.2022 10:29+1Да где loom то и наллабилити?
Gmugra
24.03.2022 16:07+1"наллабилити" (как, например, в Kotlin) в Java, похоже, не появится никогда. Обсуждения были, но там виднеются какие-то непреодолимые проблемы с обратной совместимостью. Никаких планов, насколько я знаю, нет.
Всё что есть это реализации на основе идей из JSR 305(dormant since 2012). т.е. аннотации вида @NonNull из внешних библиотек(реализаций есть несколько) ну и Optional.
Loom развивается, но там просто очень сложно. Влиятельные спикеры выражают сомнение даже в том что он войдет даже в следующий LTS (Java 21). Есть early-access build c ним. Попробовать можно. То что уже работает - впечатляет очень сильно.
orionll Автор
24.03.2022 19:15Николай Парлог (Java Developer Advocate в Oracle) считает, что первое preview Loom попадёт в JDK 20.
Gmugra
24.03.2022 19:59Я не сомневаюсь что в виде preview Loom появится в ближайших версиях. Но как именно полноценная, не preview, фича, оно, похоже, в следующий LTS не войдет. Будет отлично если я ошибаюсь :)
orionll Автор
24.03.2022 19:24-1А чем вас не устраивают аннотации JetBrains?
Gmugra
24.03.2022 20:26всем :)
Аннотации сами по себе мало что дают.
Вам в дополнение к ним нужен некий static analysis tools который, на основе аннотаций, на этапе компиляции, будет вам выявлять косяки.
Например, в случае аннотации JetBrains, IDEA играет эту роль.
А я не пользуюсь IDEA. :)Это совсем не то же самое что поддержка на уровне синтаксиса самого языка и/или стандартной библиотеки и родного компилятора.
urvanov
А IDE и пакетные менеджеры уже готовы?
orionll Автор
IDEA поддерживает 18 только в EAP вроде бы. 2021.3 не поддерживает.
Eclipse как обычно добавит поддержку через 3 месяца (либо прямо сейчас можно скачать плагин).
Maven автоматически должен работать с новыми версиями, там ничего специального не надо делать до этого.
Gradle вроде ещё не поддерживает.