Вышла общедоступная версия Java 20. В этот релиз попало около 1500 закрытых задач и 7 JEP'ов. Release Notes можно посмотреть здесь. Изменения API – здесь.
Ссылки на скачивание:
Вот список JEP'ов, которые попали в Java 20.
Паттерны записей (Second Preview) (JEP 432)
В паттерны записей, которые появились в Java 19 в режиме preview (и остающиеся в этом статусе в Java 20), было внесено три главные изменения.
Во-первых, добавилась поддержка вывода типов в записях-дженериках:
record Box<T>(T t) {} static void test(Box<String> box) { if (box instanceof Box(var s)) { // Выводится Box<String>(var s) System.out.println("String " + s); } }
Во-вторых, паттерны записей теперь могут присутствовать в заголовке улучшенного цикла for
:
record Point(int x, int y) {} static void dump(Point[] pointArray) { for (Point(var x, var y) : pointArray) { System.out.println("(" + x + ", " + y + ")"); } }
Примечание: эту возможность было решено удалить в Java 21, но она снова может появиться в будущем в другом JEP'е.
В-третьих, исчезла поддержка именованных паттернов записей. Это значит, что такой код, который компилировался в Java 19, в Java 20 уже не будет компилироваться:
if (obj instanceof Point(var x, var y) p) { // Syntax error ... }
Хотя именованные паттерны и исчезли в этом релизе, это не значит, что они исчезли насовсем. Возможно они появятся в одном из будущих релизов, когда будут более тщательно продуманы.
Паттерн-матчинг для switch
(Fourth Preview) (JEP 433)
Это уже четвёртая итерация preview паттерн-матчинга в Java. Напомним, что предыдущие три попали в Java 17, 18 и 19. В новой версии три главных изменения.
Во-первых, исчерпывающий switch
по перечислениям теперь выбрасывает MatchException
, а не IncompatibleClassChangeError
, если ни одна из меток switch
не сматчилась.
Во-вторых, упростилась грамматика меток switch
в JLS.
В-третьих, добавилась поддержка вывода типов в записях-дженериках, если они являются паттернами в switch
:
record Pair<S, T>(S first, T second) {} static void recordInference(Pair<String, Integer> pair) { switch (pair) { case Pair(var fst, var snd) -> ... // Выводится Pair<String, Integer> ... } }
Как видите, здесь JEP 433 полностью согласуется с JEP 432.
Паттерны записей и паттерн-матчинг для switch
предлагается финализировать в Java 21 (JEP 440 и JEP 441).
Virtual Threads (Second Preview) (JEP 436)
Виртуальные потоки, которые появились в Java 19, продолжают оставаться в статусе Preview API (предлагается финализировать их в Java 21). Изменений API, связанных с проектом Loom, в этом релизе нет (если не считать scoped values и structured concurrency, которые имеют инкубационный статус).
Scoped Values (Incubator) (JEP 429)
Появился новый класс ScopedValue
, который позволяет обмениваться иммутабельными данными без их передачи через аргументы методов. Он является альтернативой существующему классу ThreadLocal
.
Классы ThreadLocal
и ScopedValue
похожи тем, что решают одну и ту же задачу: передать значение переменной в рамках одного потока (или дерева потоков) из одного места в другое без использования явного параметра. В случае ThreadLocal
для этого вызывается метод set()
, который кладёт значение переменной для данного потока, а потом метод get()
вызывается из другого места для получения значения переменной. У данного подхода есть ряд недостатков:
- Неконтролируемая мутабельность (
set()
можно вызвать когда угодно и откуда угодно). - Неограниченное время жизни (переменная очистится, только когда завершится исполнение потока или когда будет вызван
ThreadLocal.remove()
, но про него часто забывают). - Высокая цена наследования (дочерние потоки всегда вынуждены делать полную копию переменной, даже если родительский поток никогда не будет её изменять).
Эти проблемы усугубляются с появлением виртуальных потоков, которые могут создаваться в гораздо больше количестве, чем обычные.
ScopedValue
лишён вышеперечисленных недостатков. В отличие от ThreadLocal
, ScopedValue
не имеет метода set()
. Значение ассоциируется с объектом ScopedValue
путём вызова другого метода where()
. Далее вызывается метод run()
, на протяжении которого это значение можно получить (через метод get()
), но нельзя изменить. Как только исполнение метода run()
заканчивается, значение отвязывается от объекта ScopedValue
. Поскольку значение не меняется, решается и проблема дорогого наследования: дочерним потоком не надо копировать значение, которое остаётся постоянным в течение периода жизни.
Пример использования ScopedValue
:
static final ScopedValue<Credentials> CREDENTIALS = new ScopedValue<>();
Credentials creds = ...
ScopedValue.where(CREDENTIALS, creds).run(() -> {
...
Connection connection = connectDatabase();
...
});
Connection connectDatabase() {
Credentials credentials = CREDENTIALS.get();
...
}
Во многих случаях ScopedValue
будет являться предпочтительной заменой ThreadLocal
. Однако когда иммутабельный подход неприменим для решения задачи, ThreadLocal
может остаться предпочтительным.
На период инкубации новое API будет находиться в модуле jdk.incubator.concurrent
.
В Java 21 scoped values, скорее всего, станут preview.
Structured Concurrency (Second Incubator) (JEP 437)
Structured concurrency, которое появилось в Java 19, остаётся в инкубационном статусе в модуле jdk.incubator.concurrent
(вместе со ScopedValue
).
Единственное отличие от предыдущей версии API – это то, что StructuredTaskScope теперь поддерживает наследование scoped values потоками, созданными внутри области видимости задачи.
Foreign Function & Memory API (Second Preview) (JEP 434)
Foreign Function & Memory API, ставшее preview в Java 19, продолжает находиться в этом статусе. API находится в пакете java.lang.foreign
.
Основные изменения в этом релизе:
- Исчез интерфейс
MemoryAddress
. Теперь адреса моделируются черезMemorySegment
с нулевой длиной. - Улучшена иерархия
sealed
интерфейсаMemoryLayout
, чтобы лучше соответствовать паттерн-матчингу дляswitch
. - Исчез интерфейс
MemorySession
. Он разделён на два интерфейсаArena
иSegmentScope
.
В Java 21 Foreign Function & Memory API останется на третье preview.
Vector API (Fifth Incubator) (JEP 438)
Векторное API всё никак не хочет становиться стабильным и остаётся в инкубационном статусе уже в пятый раз (модуль jdk.incubator.vector
). В этом релизе лишь небольшие исправления багов и улучшения производительности. Скорее всего, инкубационный статус будет оставаться до тех пор, пока необходимые фичи проекта Valhalla не появятся в режиме preview (проект Panama сильно зависит от проекта Valhalla).
Заключение
Java 20 не является LTS-релизом и будет получать обновления от Oracle только в течение полугода (до сентября 2023 года). LTS-релизом станет следующая версия, Java 21.