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

Новые API

JEP 506: Scoped Values

Ссылка на JEP

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

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

  • неограниченное время жизни;

  • неконтролируемая изменяемость;

  • затратное (по производительности) наследование значения дочерними потоками.

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

Пример:

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

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

KDF-алгоритмы — алгоритмы, безопасно генерирующие криптографические ключи из исходных секретов (паролей/ключей). Более подробно тут.

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

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

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

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

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

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

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

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

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

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

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

JEP 513: Flexible Constructor Bodies

Ссылка на JEP

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

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

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

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

JEP 503: Remove the 32-bit x86 Port

Ссылка на JEP

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

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

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

JEP 519: Compact Object Headers

Ссылка на JEP

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

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

JEP 521: Generational Shenandoah

Ссылка на JEP

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

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

  • снижение потребление памяти без увеличения пауз GC;

  • уменьшение энергопотребления и нагрузки на CPU.

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

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

Ссылка на JEP

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

Подробнее о Ahead-of-Time кэше можете прочитать в нашей предыдущей статье о нововведениях в Java.

JEP 515: Ahead-of-Time Method Profiling

Ссылка на JEP

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

Улучшения JFR

JEP 518: JFR Cooperative Sampling

Ссылка на JEP

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

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

JEP 520: JFR Method Timing & Tracing

Ссылка на JEP

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

  • MethodTiming фиксирует время выполнения методов с наносекундной точностью;

  • MethodTrace строит цепочки вызовов для критичных участков.

In Preview

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

Заключение

Полный список JEP можно найти на сайте OpenJDK.

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

Комментарии (1)


  1. mrprogre
    10.09.2025 10:43

    Шикарная статья! Максимально понятно написано в отличие от других подобных.
    Просто мысль: много народу на восьмой джаве пишет до сих пор и чаще закрывает подобные статьи, типа на потом. Было бы интересно почитать статьи именно от Вас со всеми важными различиями между восьмой и текущей. Это явно статей на 10 :)