Всем привет! ?????

Мы — Java-разработчики Т-Банка: Андрей, Арсений, Роман, Константин и Константин. Собираем интересные новости, статьи, туториалы и другие материалы из мира Java-разработки и делимся этим со всем сообществом.

В этом выпуске рассказываем, когда ждать релиз Java 27 и как Oracle планирует регулировать использование генеративного ИИ при написании кода. Посмотрим детальное интервью о Spring Framework 7 и Spring Boot 4 с самой командой создателей Spring. Почитаем, как безопасно работать с нативной памятью в многопоточной среде с помощью VarHandle. А еще изучим любопытный постмортем, посвященный расследованию раздувания памяти в контейнерах после перехода на JDK 17. Приятного чтения!

Горячий JEP

JEP 534: Compact Object Headers by Default. Компактные хедеры будут по умолчанию. Напомним, что компактные хедеры добавили в JDK 24, в JDK 25 они стали полностью доступны с помощью флага XX:+UseCompactObjectHeaders, а теперь их хотя включить по умолчанию. Компактные хедеры занимают 64 бит памяти вместо 96, за счет чего уменьшается объем используемого хипа.

Джавовые события

29 августа в штаб-квартире Т-Банка пройдет JVM Day — конференция для бэкенд-разработчиков. Идет сбор заявок на доклад для тех, кто хочет рассказать о рабочих кейсах, новых подходах или необычных практиках.

Главные новости

OpenJDK Interim Policy on Generative AI. OpenJDK выложили временную политику по использованию генеративного ИИ. Полную обещают выложить позже. Если коротко, то пока запретили любое использование ИИ на ресурсах OpenJDK. Помимо кода в репозиторий, любую информацию или картинки на ресурсах OpenJDK нельзя генерировать. При этом можно с помощью ИИ анализировать код OpenJDK и на основе анализа производить доработки руками.

Объявлен график выхода JDK 27. Марк Рейнхольд официально объявил расписание для JDK 27. Rampdown Phase One (форк от main) назначена на 4 июня 2026, GA — на сентябрь 2026. Из нацеленных JEP'ов: JEP 532 (Primitive Types in Patterns, пятое preview). Напомним, что JDK 27 не будет LTS-релизом, следующий LTS после JDK 25 ожидается в JDK 29.

Oracle Java Verified Portfolio. На JavaOne 2026 Oracle анонсировал Java Verified Portfolio (JVP) — набор инструментов, фреймворков и библиотек с официальной поддержкой Oracle и четким роадмапом. В JVP вошли JavaFX (с продлением поддержки на JDK 8 до марта 2028), Helidon и Oracle Java Platform Extension for VS Code. Лицензия и поддержка бесплатны для подписчиков OCI и Java SE Subscription. Oracle расширяет периметр enterprise-поддержки за пределы самого JDK

Oracle Critical Patch Update — апрель 2026. 21 апреля Oracle выпустил квартальный Critical Patch Update. В части Java SE — 11 патчей безопасности, из которых 7 эксплуатируются удаленно без аутентификации. Среди наиболее серьезных — CVE-2026-34282 (DoS в Networking) и CVE-2026-22016 (утечка данных через JAXP). Обновиться рекомендуется до JDK 26.0.1, 25.0.3, 21.0.11, 17.0.19, 11.0.31 или 8u491.

Интересные видео

Спринг Потрошитель — Ремейк: вооруженный Дебаггером. Возвращение легенды! Обновленный доклад «Spring-потрошитель» от Евгения Борисова. Автор уже не так сильно зацикливается на XML-конфигурации. Вместо этого объясняются новые концепции в Spring, в том числе и Programmatic Bean Registration из Spring 7, затрагивается Environment из Spring Boot.


Название немного обманчивое :) Тяжело сказать, что это полноценный ремейк и просмотр оригинального доклада не имеет смысла: автор периодически ссылается на концепции, которые он более подробно разбирал в оригинальном докладе.

You Must Avoid Final Field Mutation — Inside Java Newscast #110. В Java 26 введены флаги для ограничения изменения значений final-полей после инициализации объекта. В этом выпуске Inside Java Newscast Николай разбирает типичные случаи, когда может потребоваться применять этот антипаттерн, и приводит альтернативы, чтобы наши приложения не ударились во все тяжкие ? 

Затрагиваются сериализация, внедрение зависимостей и клонирование. В описании к видео даются ссылки на статьи с более подробным разбором описываемых практик. Общим лейтмотивом идет переход на использование конструктора. Есть текстовая версия для тех, кто не очень любит смотреть видосики.

Полезные статьи

Thread-Safe Native Memory in Java: VarHandle Access Modes Explained — статья про работу с нативной памятью через FFM API и то, как VarHandle управляет синхронизацией. Основная идея: обычные lock’и слишком тяжелые, поэтому вместо них можно использовать более низкоуровневый контроль через access modes у VarHandle.

Автор начинает с объяснения, зачем это вообще нужно.

Проблема в том, что разные CPU по-разному работают с памятью:

  • x86 — относительно строгая модель памяти.

  • ARM может агрессивно переупорядочивать операции.

Из-за этого без явных гарантий можно получить некорректное поведение в многопоточке. 

Разбираются режимы доступа:

  • plain: обычные get/set без каких-либо гарантий, возможны любые reorder’ы
    opaque: минимальные гарантии, чуть сильнее plain, но без полной синхронизации.

  • acquire / release: позволяют выстраивать happens-before-отношения между потоками, часто используются как более дешевая альтернатива volatile.

  • volatile: самый строгий режим — дает те же гарантии, что и volatile-поля.

Показано, как это все проверять через JCStress и почему такие детали начинают играть роль при работе с off-heap-памятью.

Статья хорошо иллюстрирует, что с приходом FFM API Java дает доступ к более низкоуровневым механизмам, где уже приходится явно думать про memory ordering и поведение железа.

How to develop AI agents with Spring — туториал по созданию AI-агентов на базе Spring AI. Автор начинает с определения агента. В отличие от обычного запроса к LLM, агент работает как цикл (agent loop): планирует действия, вызывает инструменты и обрабатывает результат до достижения цели. 

Пошагово разбирается реализация: 
  • настройка Spring AI и подключение LLM через конфигурацию;

  • использование prompt templates для параметризации запросов; 

  • реализация RAG через vector store (в примере — SimpleVectorStore); 

  • подключение tools, через которые агент может взаимодействовать с внешними системами. 

В качестве примера — построение REST-сервиса, который может выполнять поиск по данным с помощью natural language. Отдельный акцент на том, что Spring AI использует привычные подходы Spring: 

  • dependency injection; 

  • автоконфигурацию; 

  • работу через интерфейсы. 

За счет этого AI-логика встраивается в приложение так же, как и любая другая бизнес-логика.

Junie CLI Now Connects to Your JetBrains IDE. Junie CLI — это AI coding agent от JetBrains, который работает из терминала и умеет выполнять задачи над кодом по описанию на естественном языке: например, исправить баг, реализовать фичу или написать тесты.

В отличие от обычных AI-ассистентов, Junie работает как агент:
  • понимает структуру проекта; 

  • может запускать код и тесты;

  • выполняет цепочку действий, а не просто генерирует ответ. 

Junie — LLM-agnostic, можно использовать разные модели (OpenAI, Anthropic, Google и др.) и переключаться между ними. В обновлении добавили интеграцию с IDE от JetBrains. Теперь CLI может подключаться к запущенной IDE и использовать ее внутреннюю информацию: индекс проекта, семантический анализ, конфигурации сборки и тестов.

Агент фактически «видит» проект так же, как его видит разработчик в IDE, и работает с тем же контекстом. Подключение происходит автоматически, без дополнительной настройки, если IDE уже запущена.


Cyrock.AI Knowledge Fabric: The Petabyte-Scale Memory Layer for Enterprise AI

— статья про новую архитектуру слоя памяти для AI-систем, построенную вокруг идеи отказа от классических баз данных. Основная проблема, которую поднимает автор, — традиционные vector-/graph-базы плохо масштабируются для AI-нагрузок.


Традиционные vector-/graph-базы:

  • построены как монолитные always-on-серверы; 

  • требуют постоянного резервирования ресурсов; 

  • плохо масштабируются за пределами ~ 10 TB данных. 

В Cyrock предлагают другой подход, так называемую cell-based-архитектуру. Когда вместо одного сервера используется сеть маленьких data cells, каждая ячейка поднимается только при запросе и после обработки данных завершает работу.

Новый подход — перенос идеи serverless на уровень хранения данных: нет нагрузки → нет потребления CPU, нагрузка есть → система масштабируется. 

Каждая ячейка занимает очень мало ресурсов (~ 0,001 CPU, ~ 100 MB RAM), может кэшировать «горячие» данные и работает независимо от остальных.

Отдельно разбирается работа с графами и vector search: данные разбиваются на подграфы, каждый подграф загружается в память по требованию, что позволяет работать с очень большими графами без загрузки всего в RAM. В итоге система объединяет vector search, graph search, full-text search и caching 

в один слой памяти. Этот слой работает поверх Kubernetes и масштабируется до petabyte-уровня.

Отдельный акцент в статье на экономии ресурсов: за счет отключения неиспользуемых ячеек заявляется до 80% снижения затрат на инфраструктуру.

Natural Language Data Access in Java — статья о том, как «поговорить с базой данных» на естественном языке, используя стек Hibernate + Quarkus + LangChain4j. Основная идея — убрать необходимость писать SQL и дать возможность формулировать запросы к данным через LLM.

Генерация SQL происходит не «вслепую», а на основе метаданных Hibernate: 

используется доменная модель (entity, связи, типы), LLM опирается на структуру ORM, а не на сырые таблицы.

Ключевой компонент — Hibernate Assistant: принимает запрос на естественном языке, преобразует его в запрос к ORM и возвращает результат. Получается слой между LLM и базой, который понимает структуру данных, ограничивает возможные запросы и снижает риск некорректного SQL.

В статье продемонстрирована интеграция с Quarkus и LangChain4j. LangChain4j используется как обертка над LLM, Quarkus — как runtime и точка входа (REST / MCP), а Hibernate — как источник структуры данных. Отдельно упоминается использование MCP (Model Context Protocol), чтобы подключать такие сервисы к AI-агентам. В итоге приложение превращается в своего рода data node, к которому можно обращаться через natural language, не зная ни SQL, ни схемы базы.

Цикл статей о шаблонных ошибках в коде, влияющих на производительность, пока вышло две части из трех.

Java Is Fast. Your Code Might Not Be рассказывает о самых типичных проблемах:

  • Конкатенация строк в циклах — копирование со сложностью O(n²) из-за неизменяемости.

  • Итерация стримов со сложностью O(n²) внутри циклов — потоковая передача всего списка по элементам.

  • String.format() в местах с высокой нагрузкой — самый медленный построитель строк, анализирует формат при каждом вызове.

  • Автоупаковка в местах с высокой нагрузкой — миллионы одноразовых объектов-оберток.

  • Исключения в местах с высокой нагрузкой — при создании исключения fillInStackTrace() проходит весь стек вызовов.

  • Слишком большой synchronized-блок — одна блокировка становится узким местом.

  • Пересоздание объектов, которые можно переиспользовать — ObjectMapper, DateTimeFormatter, Gson на каждом вызове.

  • Virtual thread pinning (JDK 21–23) — synchronized-блок, блокирующий операции ввода-вывода при использовании виртуальных потоков.

One Method Was Using 71% of CPU. Here's the Flame Graph. | Jonathan Vogel на примере рассматривается, как работать с JFR и JMC. Для начала нужно записать JFR, чтобы появился файл, который можно использовать в JMC:

  1. Открыть файл в JMC.

  2. Начать с первого обзорного экрана, чтобы понять суть проблемы.

  3. Перейти в раздел Allocations при увеличении количества объектов в куче и давлении на сборщик мусора.

  4. Перейти в раздел Method Profiling и посмотреть Flame Graph при высокой загрузке ЦП.

  5. Перейти в Lock instances при медленном времени отклика при использовании обычного процессора.

  6. Сначала устранить самую навязчивую проблему, затем изменить профиль и повторить процедуру.

Раздувание памяти JDK 17 в контейнерах: разбор инцидента — перевод статьи JDK 17 Memory Bloat in Containers: A Post-Mortem. Любопытный постмортем массового инцидента, случившегося после перехода с JDK 8 на 17. Спустя несколько часов после релиза резко выросло потребление нативной памяти в контейнерах. Начались перезагрузки из-за OOMKill.

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

Сама история произошла в 2022 году, и баг с некорректным определением CPU в JDK давно поправили, очень рекомендуем для ознакомления. Статья помогает на примере понять, как и для чего JVM использует память вне хипа.

The Spring Team on Spring Framework 7 and Spring Boot 4 - InfoQ. InfoQ взяли большое Q&A-интервью у core-команды по поводу мажорных релизов Spring 7 и Boot 4. Разработчики из первых рук разбирают логику новых архитектурных решений и отвечают на практические вопросы по миграции.

Объясняют, что на деле дает модуляризация Boot 4 помимо похудения jar-файлов и почему механизмы resilience затащили напрямую в ядро. Участники обсудили новый способ версионирования API на основе заголовков запроса, нюансы переезда на Jackson 3 вместе с JSpecify и влияние AI-ассистентов на развитие Spring Tools.

JPA 4. Переосмысление Hibernate / Хабр. Команда Spring АйО перевела статью Гэвина Кинга о первом milestone JPA 4. Несмотря на то, что уже вышла GA версия, статья все еще очень полезная и рассказывает о самых важных фичах.

JPA 4 — крупнейшее обновление спецификации с 2009 года. Главная фича — появление EntityAgent. Это стандартный метод работы в обход Persistence Context: возможность выполнять прямые запросы к БД (insert, update) без managed сущностей и с новым lifecycle ивентами: @PreInsert, @PostUpsert, @PreDelete. Помимо этого появилось много более мелких, но не менее важных фичей: статические типизированные запросы с проверкой при компиляции, возможность глобально задать LAZY для one-to-* связей по умолчанию и многое другое.

Любопытный подкаст

How JDK 26 Improves G1's Throughput — Inside Java Podcast #54 — эпизод посвящен JEP 522 (G1 GC: Improve Throughput by Reducing Synchronization), который вошел в JDK 26. Обсуждается, как были оптимизированы write barriers в G1, за счет чего удалось снизить накладные расходы на синхронизацию между потоками приложения и потоками GC. Полезно послушать тем, кто хочет понять, почему G1 в JDK 26 стал заметно быстрее.

Просто интересное

The Best Library Might Do Less — небольшая и простенькая статья на тему YAGNI и KISS с примечательным чек-листом с вопросами ближе к концу статьи. Общую тематику вопросов можно сформулировать так: «При разработке смотрите на реальную потребность пользователей в функционале, а не на ваши ощущения». Когда мы делаем что-то для себя — слушать нужно себя, но даже так иногда нужно уметь отказаться от того, чтобы наделать лишнего. Чем больше функционала, тем сложнее его поддерживать.

Чек-лист

Вопросы для самопроверки при разработке библиотеки:

  • Каковы минимальные требования к моей библиотеке?

  • Какие самые распространенные потребности у моей библиотеки?

  • Какова наиболее распространенная последовательность событий для моих пользователей?

  • Какие наиболее распространенные проблемы возникают в существующих библиотеках?

  • Какие наиболее распространенные ошибки могут возникнуть во время использования?

  • Какие ошибки могут возникнуть чаще всего ? Те, которые трудно и важно правильно исправить?

  • Какие footguns существуют в этой проблемной области? Есть ли что-то, что пользователям необходимо явно запретить? Можно ли сделать эти действия невозможными?

  • Какую лексику или метафоры уже используют мои пользователи в этой области?

  • Каков самый простой «оптимальный сценарий» (то есть когда ошибок не возникает) при использовании функционала, который я пытаюсь реализовать?

  • Могут ли пользователи со сложными потребностями по-прежнему получать пользу от того, что я создаю, даже если я не буду выполнять всю работу за них? Каким образом?

  • Можно ли улучшить ситуацию, убрав что-нибудь? Включая требования?

Константин Польщиков

Думаю, что чек-лист применим при разработке не только библиотек, но и приложений, сервисов и любых других программных продуктов.

S3 Files and the changing face of S3 | All Things Distributed. В блоге Werner Vogels (CTO AWS) вышла статья о новой фиче — S3 Files. Она дает возможность монтировать S3-бакеты как локальную файловую систему в EC2, контейнерах или Lambda. Раньше, чтобы обработать объект из S3, его приходилось сначала выкачивать локально, теперь же бакет можно подключить как обычную файловую систему и работать с данными в нем через любые стандартные библиотеки, работающие с файловой системой.


Фича позволит убрать кучу boilerplate-кода для взаимодействия с S3: легаси-приложения, ML-пайплайны и утилиты, заточенные под файлы, начинают работать с S3 без дополнительных адаптеров.

Why Java Developers Over-Trust AI Suggestions. Автор рассматривает, как эвристика беглости склоняет разработчиков принимать ошибочный код, сгенерированный AI. Дело в том, что AI генерирует очень строгий с визуальной точки зрения код и мозг заочно воспринимает его как верный.
Подсвечивается несколько рисков, специфичных для Java. При этом автор отмечает, что дополнительные инструменты могут отловить некоторые ошибки, а на код-ревью сгенерированный код стоит проверять так же тщательно, как если бы его принес разработчик.

Константин Максимов

Хочется больше развернуть тему инструментов. В эпоху AI становятся особенно важны автоматические и при этом детерминированные проверки качества: тесты, проверки зависимостей, линтеры, статические анализаторы, контроль архитектуры проекта с помощью таких инструментов, как ArchUnit.

Свежие релизы

Google ADK for Java 1.0.0. Google выпустил стабильную версию Agent Development Kit для Java. Фреймворк позволяет строить AI-агентов с поддержкой Human-in-the-Loop (через ToolConfirmation), межагентного взаимодействия по протоколу A2A, сжатия контекста для длинных сессий и персистентного хранения состояния через Firestore/Vertex AI. Из коробки идут инструменты для Google Maps, исполнения кода в контейнерах и работы с веб-контентом. Поддерживаются модели OpenAI, Anthropic, Google и др.

Koog for Java (JetBrains) + интеграция с Spring AI. JetBrains представил Java API для своего фреймворка Koog — инструмента для построения enterprise-ready AI-агентов на JVM. Поддерживаются три стратегии оркестрации: функциональная (code-based с type-safe-подзадачами), графовая (FSM с нодами и ребрами) и планирующая (GOAP — автоматический выбор порядка выполнения). Из приятного — OpenTelemetry-обсервабилити и сжатие истории чата. В апреле вышла интеграция с Spring AI — подключается тремя зависимостями поверх существующей конфигурации.

Hibernate ORM 7.3 Final. 7 апреля вышел Hibernate ORM 7.3. Из заметного: новый enum KeyType, позволяющий выполнять find() и findMultiple() по natural id, а не только по primary key. Добавлена аннотация @NaturalIdClass — аналог @IdClass, но для составных natural id. Появилась поддержка Jackson 3. Также bytecode enhancer теперь автоматически генерирует дефолтный конструктор для entity-классов, если его нет.

Spring Boot 4.1.0-RC1. 23 апреля вышел первый release candidate Spring Boot 4.1. В нем 113 улучшений, включая поддержку OpenTelemetry SDK environment variables, защиту от SSRF через InetAddressFilter в HTTP-клиенте и LazyConnectionDataSourceProxy. GA ожидается в мае 2026.

Apache Maven 4.0.0-rc-5. Maven 4 продолжает движение к GA — вышел пятый release candidate. Из ключевых нововведений Maven 4 в целом: разделение Build POM и Consumer POM (потребители зависимости видят «чистый» POM, без build-специфики), новая модель POM 4.1.0, хуки before:/after: для фаз жизненного цикла, новый тип пакетирования BOM и минимум Java 17 для работы. Для миграции с Maven 3 появилась утилита mvnup (mvnup check / mvnup apply).

Спасибо за прочтение! Ждем вашу обратную связь в комментариях. Увидимся через месяц ? Присылайте материалы, если встретили что-то интересное, — опубликуем в следующем выпуске!

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


  1. TimurZhoraev
    06.05.2026 15:48

    В 21м веке так и не завезли в JVM элементы с базами данных аналогичных SQL наподобие VoltDB, что уже собственно сделано нативным образом. Что касается Гугла - то проще уже сразу писать:
    make a bubble sort at jvm bytecode. args: array of long int of 100 values

    BTTF в 70-е
    // --- Initialization ---
    0:  aload_0             // Push long[] array
    1:  arraylength         // Get length
    2:  istore_1            // Store length in n (slot 1)
    3:  iconst_0            // i = 0
    4:  istore_2            // Store i (slot 2)
    
    // --- Outer Loop Start (i < n - 1) ---
    5:  iload_2             // Push i
    6:  iload_1             // Push n
    7:  iconst_1            
    8:  isub                // n - 1
    9:  if_icmpge 70        // If i >= n - 1, exit outer loop
    
    12: iconst_0            // j = 0
    13: istore_3            // Store j (slot 3)
    
    // --- Inner Loop Start (j < n - i - 1) ---
    14: iload_3             // Push j
    15: iload_1             // Push n
    16: iload_2             // Push i
    17: isub                // n - i
    18: iconst_1
    19: isub                // n - i - 1
    20: if_icmpge 64        // If j >= n - i - 1, exit inner loop
    
    // --- Comparison (arr[j] > arr[j+1]) ---
    23: aload_0             
    24: iload_3             
    25: laload              // Push arr[j] (long)
    26: aload_0             
    27: iload_3             
    28: iconst_1            
    29: iadd                // j + 1
    30: laload              // Push arr[j+1] (long)
    31: lcmp                // Compare longs (-1, 0, or 1)
    32: ifle 58             // If arr[j] <= arr[j+1], skip swap
    
    // --- Swap Logic ---
    35: aload_0             
    36: iload_3             
    37: laload              
    38: lstore 4            // temp = arr[j] (slots 4-5)
    
    40: aload_0             
    41: iload_3             
    42: aload_0             
    43: iload_3             
    44: iconst_1            
    45: iadd                
    46: laload              
    47: lastore             // arr[j] = arr[j+1]
    
    48: aload_0             
    49: iload_3             
    50: iconst_1            
    51: iadd                
    52: lload 4             
    54: lastore             // arr[j+1] = temp
    
    // --- Increment & Loop Back ---
    58: iinc 3, 1           // j++
    61: goto 14             // Repeat inner loop
    
    64: iinc 2, 1           // i++
    67: goto 5              // Repeat outer loop
    
    70: return              // End

    И зачем тогда все эти высокоуровневые конструкции...