﻿# Нововведения Java 25

Java не стоит на месте и продолжает активно развиваться\. Скоро выйдет уже 25\-я версия языка\. В этом релизе изменили работу с boilerplate\-кодом и конструкторами, а также отказались от поддержки устаревших систем\. Обо всех этих и других нововведениях расскажем в статье\.

![1284_java25_ru/image1.png](https://import.viva64.com/docx/blog/1284_java25_ru/image1.png)

## Новые API

### JEP 506: Scoped Values

[Ссылка на JEP](https://openjdk.org/jeps/506)

Как часто вы использовали `ThreadLocal`? Даже не так: слышали ли вы о нём? Если коротко, `ThreadLocal` — это контейнер, хранящий уникальное значение переменной для каждого потока\.

С ходу тут и не скажешь, какие проблемы могут возникнуть\. Но они есть и довольно серьёзные:

* неограниченное время жизни;
* неконтролируемая изменяемость;
* затратное \(по производительности\) наследование значения дочерними потоками\.

В этом релизе появился новый механизм `ScopedValue`, решающий перечисленные проблемы\. 

Пример:

```cpp
ScopedValue<FrameworkContext> CONTEXT = ScopedValue.newInstance();  
  
void serve(Request request, Response response) {  
    var context = createContext(request);  
    ScopedValue.where(CONTEXT, context)  
            .run(() -> handle(request, response));  
}  
  
void handle(Request request, Response response) {  
    // ....
    readKey(key);  
    // ....
}  
  
Key readKey(String key) {  
    var context = CONTEXT.get();  
    var connection = getConnection(context);  
    return connection.readKey(key);  
}
```

Здесь с помощью `ScopedValue#where` настраивается окружение, а `#run` запускает `Application#handle` с этим контекстом\. Сразу после выхода из метода контекст чистится\.

### JEP 510: Key Derivation Function API

[Ссылка на JEP](https://openjdk.org/jeps/510)

Теперь в Java есть единый встроенный способ для работы с KDF\-алгоритмами\.

> KDF\-алгоритмы — алгоритмы, безопасно генерирующие криптографические ключи из исходных секретов \(паролей/ключей\)\. Более подробно [тут](https://ru.wikipedia.org/wiki/%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BA%D0%BB%D1%8E%D1%87%D0%B0)\.

Раньше для разных алгоритмов требовались разные подходы, теперь всё просто:

```cpp
KDF hkdf = KDF.getInstance("HKDF-SHA256");  

AlgorithmParameterSpec params =  
        HKDFParameterSpec.ofExtract()  
                .addIKM(initialKeyMaterial)  
                .addSalt(salt)
                .thenExpand(info, 32);  
SecretKey key = hkdf.deriveKey("AES", params);
```

Все танцы с бубном с `SecretKeyFactory` и `PBEKeySpec` для PBKDF2 или возня с `HKDFParameterSpec` теперь в прошлом\. Один API, чтобы управлять всеми\.

Нововведения в синтаксисе

### JEP 511: Module Import Declarations

[Ссылка на JEP](https://openjdk.org/jeps/511)

Настоящий подарок для тех, кто устал от бесконечных списков импортов\. Теперь можно импортировать весь модуль одной строкой\. Особенно элегантно это решение смотрится в паре с JEP 512, позволяя создавать лаконичные, почти скриптовые сценарии, без потери строгости типов\.

Вот как это выглядит в комбинации с компактными `main`\-методами:

```cpp

import module org.slf4j;

Logger log = LoggerFactory.getLogger("MyAppLogger");

void main() {
    Stream<String> stringStream = ThreadLocalRandom.current().longs(10)
            .mapToObj(String::valueOf);

    for (var string : (Iterable<String>) (stringStream::iterator)) {
        log.info(string);
    }
}
```

### JEP 512: Compact Source Files and Instance Main Methods

[Ссылка на JEP](https://openjdk.org/jeps/512)

Пожалуй, одно из самых заметных изменений для каждого разработчика\. Борьба с boilerplate вышла на новый уровень\.

Наконец\-то можно забыть про обязательные `public static void main(String[] args)` для простых скриптов и утилит\. Язык становится более доступным для новичков и приятным для опытных разработчиков, которые ценят лаконичность\. Под капотом это работает за счёт неявного объявления класса и автоматического импорта модуля `java.base`\. А для ещё большего удобства в `java.lang` появился новый класс `IO` с базовыми методами ввода\-вывода\.

> Boilerplate\-код — это повторяющийся шаблонный код, который приходится писать вручную для решения стандартных задач, но при этом он несёт мало уникальной логики\.

Достаточно лишь два раза в день\.\.\.

```cpp
void main() {
  IO.println("I'm still java. For now");
}
```

\.\.\. и голова болеть не будет\.

### JEP 513: Flexible Constructor Bodies

[Ссылка на JEP](https://openjdk.org/jeps/513)

Это то, о чём многие мечтали годами\. Возможность писать код до вызова `super()` или `this()` — это не просто синтаксический сахар, а фундаментальное упрощение логики инициализации объектов\. После preview в Java 22 фича доработана и позволяет не только валидировать аргументы, но и безопасно инициализировать поля, решая классические проблемы с порядком выполнения кода, которые находила [одна из диагностик](https://pvs-studio.ru/ru/docs/warnings/v6052/) PVS\-Studio :\)

_Не будем указывать пальцем, но это всегда было ограничение языка, а не байт\-кода, JVM или чего\-то ещё\._

```cpp
Sandbox(String key) {
    if (!key.startsWith("sandbox:"))
        throw new IllegalArgumentException(key);
    super(key);
}
```

Изменения в платформе Java

### JEP 503: Remove the 32\-bit x86 Port

[Ссылка на JEP](https://openjdk.org/jeps/503)

Официально прощаемся с 32\-битными x86\-системами\.

Напомним: в прошлом релизе отправили в утиль поддержку 32\-битной Windows, а теперь добили и остальные платформы \(Linux x86, macOS\)\. Причина проста: поддержка древнего железа требует немалых усилий, а пользователей таких систем совсем\-совсем мало\.

Если вы ещё используете 32\-битную JVM \(вау\!\), пора задуматься об обновлении\.

### JEP 519: Compact Object Headers

[Ссылка на JEP](https://openjdk.org/jeps/519)

Сжать нельзя выделить\.

Каждый объект в Java\-куче имеет скрытый заголовок — как паспорт с метаданными\. До Java 25 в 64\-битных JVM он весил 12 байт\. Теперь его можно ужать до 8 байт флагом `-XX:+UseCompactObjectHeaders`\.

### JEP 521: Generational Shenandoah

[Ссылка на JEP](https://openjdk.org/jeps/521)

> Shenandoah — низкопаузный параллельный сборщик мусора, работающий конкурентно с приложением\. Основная задача: минимизировать stop\-the\-world паузы \(<10 мс\) даже на терабайтных хипах\. Вместо привычных поколений использует регионы фиксированного размера\.

Теперь Shenandoah официально поддерживает поколения \(ранее это было экспериментальной фичей\): регионы могут быть молодыми или старыми\. Зачем?

* снижение потребление памяти без увеличения пауз GC;
* уменьшение энергопотребления и нагрузки на CPU\.

Ahead\-of\-Time оптимизации

### JEP 514: Ahead\-of\-Time Command\-Line Ergonomics

[Ссылка на JEP](https://openjdk.org/jeps/514)

Java понемногу старается упростить себя\. В том числе и CLI\. Теперь для создания новомодного AOT\-кэша нужен только один флаг: `-XX:AOTCacheOutput=<file>`\. 

Подробнее о Ahead\-of\-Time кэше можете прочитать в нашей [предыдущей статье о нововведениях в Java](https://pvs-studio.ru/ru/blog/posts/java/1233/)\.

### JEP 515: Ahead\-of\-Time Method Profiling

[Ссылка на JEP](https://openjdk.org/jeps/515)

AOT\-кэш развивается\. В этом релизе в AOT добавили возможность сохранять профили выполнения методов\. Теперь JVM может применить оптимизации JIT сразу, используя кэш, не дожидаясь сбора статистики выполнения\. Соответственно, приложения в продакшене быстрее запускаются и достигают пиковой производительности\.

Улучшения JFR

### JEP 518: JFR Cooperative Sampling

[Ссылка на JEP](https://openjdk.org/jeps/518)

Профилирование производительности становится точнее\! Раньше JFR использовал прерывания потоков для сбора данных, что могло искажать реальную картину при высокой нагрузке\.

Теперь же реализована кооперативная выборка: потоки приостанавливаются в безопасных точках \(safepoints\), чтобы отдать статистику\. Данные остаются консистентными, а влияние на производительность минимально\.

### JEP 520: JFR Method Timing & Tracing

[Ссылка на JEP](https://openjdk.org/jeps/520)

Хотите не только знать, где тормозит код, но и почему? Новые события в JFR дают ответ:

* `MethodTiming` фиксирует время выполнения методов с наносекундной точностью;
* `MethodTrace` строит цепочки вызовов для критичных участков\.

## In Preview

В качестве предварительного просмотра в релиз включили следующие JEP'ы:

* [JEP 470:  PEM Encodings of Cryptographic Objects \(Preview\)](https://openjdk.org/jeps/470);
* [JEP 502:  Stable Values \(Preview\)](https://openjdk.org/jeps/502);
* [JEP 505:  Structured Concurrency \(Fifth Preview\)](https://openjdk.org/jeps/505);
* [JEP 507:  Primitive Types in Patterns, instanceof, and switch \(Third Preview\)](https://openjdk.org/jeps/507);
* [JEP 508:  Vector API \(Tenth Incubator\)](https://openjdk.org/jeps/508);
* [JEP 509: JFR CPU\-Time Profiling](https://openjdk.org/jeps/509)\.

## Заключение

Полный список JEP можно найти на [сайте OpenJDK](https://openjdk.org/projects/jdk/25/)\.

Эволюция Java продолжается, и 25\-й релиз отличное тому доказательство\. Язык целенаправленно движется в сторону увеличения производительности \(AOT, Shenandoah\), уменьшения boilerplate \(компактный синтаксис\) и усиления безопасности \(KDF\)\. При этом команда разработки демонстрирует взвешенный подход, не ломая обратную совместимость\. Всё как всегда: шаг за шагом, без революций, но с постоянным улучшением уже знакомого и любимого инструмента\.