Виммельбух, 3, перетяжка
Виммельбух, 3, перетяжка
Виммельбух, 3, перетяжка

Обзор фич LTS-релиза Java 21: в новый год с новой Java

Новости

Обзор фич релиза Java 21, который вышел в сентябре 2023. Возвращается золотой век Java-разработки.

2К открытий9К показов
Обзор фич LTS-релиза Java 21: в новый год с новой Java

Давайте быстро пробежимся по основным фичам релиза Java 21, который вышел в сентябре 2023. Факт в том, что со временем переходить на него всё равно придется, нравится вам это или нет. Но большое количество новых интересных штук сделает этот переход более приятным. Большинство из этих изменений не годны для использования в продакшене, но вполне функциональны и позволяют вам оценить перспективу развития платформы. И задуматься вот о чем: возвращается золотой век, когда быть Java-разработчиком снова максимально актуально, интересно и полезно.

Финализированные инструменты

В Java 21 есть всего три полностью финализированных фичи. Это то, что можно использовать в продакшене прямо сейчас.

Virtual Threads

Виртуальные потоки — флагманская фича Java 21. Она позволяет запускать потоки в огромном количестве — тысячами, десятками тысяч. Это имеет под собой вполне конкретную практическую почву. Сетевой стек Java так странно написан, что на каждое сетевое соединение раньше нужно было выделять по целому отдельному “нативному” потоку операционной системы. Таких потоков нельзя сделать много, по факту, одна из практик — сделать их количество равным или чуть меньшим количеству ядер процессора вашего сервера. Очевидно, это ограничивает производительность любых сетевых приложений. И будем честными, приложения с веб-интерфейсом или веб-API — это то, чем занимается большинство джавистов.

Виртуальные потоки умеют совместно использовать один и тот же “нативный” тред операционной системы. Пока один виртуальный поток заблокирован задачей типа чтения из базы данных или из файла, его “потоком-носителем” могут пользоваться соседи и делать в нем какие-то вычисления. Типичное веб-приложение с CRUD-ами только тем и занимается, что ждёт ответа базы данных, поэтому эта оптимизация супер актуальна. Она легко может повысить отзывчивость приложения в целых два раза, и сделать его устойчивым и быстрым в тех случаях, когда раньше приходилось закупать дополнительные сервера.

Виртуальные потоки можно делать руками с помощью разнообразных функций стандартной библиотеки. Но куда важнее, что все основные фреймворки адаптировались под использование виртуальных тредов и создают их автоматически. Вам не нужно писать вообще никакого кода, ускорение приложений происходит магически. Всё, что вам нужно сделать — обновиться до Java 21, и перейти на самые свежие версии ваших веб-фреймворков (например, на Spring 3.2 и выше).

Record Patterns

Эта фича (JEP 440) позволяет избавиться от мусорного кода с разыменованием полей через instanceof. То, что раньше было написано вот так:

			record Point(int x, int y) {}

static void printSum(Object obj) {
    if (obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}
		

Теперь можно записать новым, компактным и устойчивым к ошибкам способом:

			static void printSum(Object obj) {
    if (obj instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}
		

Pattern Matching for switch

Эта фича (JEP 441) позволяет делать паттерн-матчинг, похожий на то, что мы имеем в других языках (например, в Scala). Это позволяет писать более удобный и читаемый код, который часто используется при программировании алгоритмов обхода графов, в компиляторах, и так далее.

В Java 8 нам нужно было писать вот такой некрасивый код, который грозит развалиться при любой модификации:

			static String formatter(Object obj) {
    String formatted = "unknown";
    if (obj instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (obj instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (obj instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (obj instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;
}
		

В Java 21 для этого есть специальная синтаксическая конструкция:

			static String formatterPatternSwitch(Object obj) {
    return switch (obj) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> obj.toString();
    };
}
		

Новые возможности

Некоторые возможности в языке продолжают улучшать на протяжении многих лет и релизов Java. В Java 21 из них только изменения в ZGC готовы для продакшена, все остальные относятся к preview-версиям фич на различных стадиях разработки.

  • ZGC, учитывающий поколения (JEP 439). Основной масштабируемый сборщик мусора в JDK сейчас ZGC.
    В Java 21 он научился делить все объекты на поколения, и собирать их по отдельности. Поскольку большинство объектов умирают молодыми, а старые живут дольше, на сборку молодых уходит меньше ресурсов, и при этом высвобождается больше памяти. Это улучшает утилизацию памяти и процессора.
  • Улучшено API и произведены оптимизации производительности в двух основных “нативных” проектах, которые помогают в машинном обучении и работе с большими данными. Foreign Function & Memory API (JEP 442) занимается нативным доступом к памяти и функциям нативных библиотек. Это позволяет удобно обращаться к быстрому C++ коду и работать с реальной быстрой оперативной памятью. Vector API (JEP 448) позволяет писать такой код, который компилятор потом сможет скомпилировать в векторные инструкции процессора, отчего этот код может начать выполняться быстрее (иногда — сильно быстрее!).
  • Улучшено API для двух новых проектов, посвященных работе с
    многопоточностью. Структурная многопоточность (structured concurrency, JEP 453) — это новая фундаментальная часть стандартной библиотеки, позволяющая писать хорошо понятный многопоточный код. Scoped Values (JEP 446) — улучшенная замена для thread locals. Они неизменяемые, не такие сложные и потребляют меньше памяти. Обе технологии специально спроектированы и хорошо работают вместе с инфраструктурой, предоставляемой
    виртуальными потоками.

Java 21 в России

Как вы, наверное, знаете, зарубежные дистрибутивы типа Oracle JDK и других поставщиков уже недоступны в России из-за санкционных ограничений: их запрещено использовать на законодательном уровне. К счастью, у нас есть возможность продолжать использовать Java на проде с помощью Axiom JDK.

Кроме всего, что мы и так ожидаем от дистрибутива JDK для продакшена, Axiom JDK можно использовать в системах с требованием на присутствие JDK в Реестре Российского ПО, и на жесткие требования Критической Информационной Инфраструктуры (КИИ) по четвертому уровню доверия регулятора ФСТЭК. Благодаря этому, например, Axiom JDK сейчас используется для процессинга и клиринга карт «Мир» и в Системе Быстрых Платежей, то есть, более ста миллионов граждан России каждый день косвенно используют этот дистрибутив JDK.

У Java 21 впечатляющий срок поддержки: Oracle (на международном рынке) будет поддерживать ее до 2031 года, а Axiom JDK (в России) – на год больше, до 2032. То есть Java 21 с нами надолго.

Заключение

Java 21 — это новая “основная” версия Java, на которую рекомендуется обновляться всем. Прежде всего, из-за сроков поддержки, виртуальных тредов и изменений в веб-фреймворках (типа Spring Boot), которые их поддерживают.

Переход на Java 21, в большинстве случаев, довольно безболезненный и понятный. По крайней мере, если вы уже используете Java 11 и не обременены легаси времен Java 6 (в этом случае вам помогут инженеры Axiom JDK, они поддерживают старые версии). Начните использовать Java 21 (Axiom JDK 21 в России), обновите Spring и попробуйте запустить на нем свой проект — вполне возможно, результаты не заставят себя ждать.

Следите за новыми постами
Следите за новыми постами по любимым темам
2К открытий9К показов