4 июня(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqvL6bDw
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱2
Optional.stream()
появился в Java 9 и позволяет превратить Optional<T>
в Stream<T>
длины 0 или 1. Зачем это нужно?📌 Когда применять?
◾️ 🧠 Интеграция с цепочками Stream API: если у вас есть коллекция
Optional<T>
, можно собрать все непустые значения без дополнительных проверок:
List<Optional<User>> userOptionals = …;
List<User> users = userOptionals.stream()
.flatMap(Optional::stream) // из каждого Optional либо 1 элемент, либо пусто
.collect(Collectors.toList());
Без
Optional.stream()
пришлось бы делать что-то вроде filter(Optional::isPresent).map(Optional::get)
.◾️ 🧠 При операциях над вложенными опционалами: когда в потоке у вас
Optional<Something>
и вы хотите «сливать», а не оставлять пустые обёртки.💡 Совет:
Если вы строите конвейер обработки данных, а на каком-то шаге может не быть значения — Optional.stream()
поможет аккуратно пропустить «пустышки» и не ломать последующие операции.
⚠️ Но вот в чём «подводные камни» и почему нельзя злоупотреблять:
1. Потеря явности
◾️ Когда вы где-то просто хотите проверить: есть ли значение в
Optional
, — использование stream()
создаёт впечатление, что у вас реально коллекция элементов, хотя всего лишь 1 или 0. Для простых случаев ifPresent()
, map()
, orElse()
читается понятнее.
// Менее канонично:
optionalValue.stream().forEach(v -> doSomething(v));
// Лучше:
optionalValue.ifPresent(v -> doSomething(v));
2. Ненужные накладные расходы
◾️ Каждый вызов
Optional.stream()
создаёт объект стрима и небольшую внутреннюю структуру, что на горячем участке кода (в tight loop) может сказаться на производительности. Если вместо него можно обойтись map().orElse()
, задумайтесь о легковесном варианте.3. Скрытые баги
◾️ Если вы по ошибке используете
Optional.stream()
в одиночном случае (не в контексте объединения множества опционалов), код может стать менее очевидным. Например:
// Что тут происходит?
Stream.of(opt1, opt2, opt3)
.flatMap(Optional::stream)
.findFirst();
Казалось бы, надо искать первый непустой, но читающий код может не сразу понять логику: а вдруг нужно просто взять любое значение, а не первой в списке? Лушче явно:
Optional<User> result = opt1.isPresent() ? opt1
: opt2.isPresent() ? opt2
: opt3;
4. Лишняя сложность
◾️ В ситуациях, когда Optional появляется из map/filter в одном стриме, а потом вы вновь оборачиваете результат в Optional, лучше сразу строить последовательность через
flatMap
и filter
без промежуточных Optional
.💡 Пример «полезного» применения:
List<Order> orders = getOrders();
// Для каждого заказа пытаемся получить пользователя из БД,
// но он может быть не найден (Optional<User>).
List<Optional<User>> maybeUsers = orders.stream()
.map(o -> userRepository.findById(o.getUserId()))
.toList();
// Теперь формируем список уже «существующих» юзеров:
List<User> users = maybeUsers.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
Здесь
Optional.stream()
полностью оправдан: сразу избавляемся от «пустых» опционалов.💡 Анти-паттерн:
Не используйте Optional.stream()
внутри метода, который ожидает ровно одно значение или бросает исключение, если опционал пуст.
// Плохо:
User user = optionalUser.stream()
.findFirst()
.orElseThrow(() -> new NotFoundException("User not found"));
// Лучше так:
User user = optionalUser
.orElseThrow(() -> new NotFoundException("User not found"));
В первом случае мы заводим стрим без смысла, во втором — прямой и понятный код.
Итого:
◾️ 🧠 Используйте
Optional.stream()
только когда действительно нужно объединить несколько Optional-ов в один Stream и пропустить пустые.◾️ ⚠️ В одиночных сценариях проверки и извлечения значения он избыточен и даже снижает читабельность и производительность.
👉@BookJava
👍4🤡1
30 лет Java: от провалившегося гаджета до фундамента разработки ПО
Некоторые языки программирования, например Rust, Go и TypeScript, считаются крутыми. Другие, в том числе Cobol и Java, «скучны». Однако пусть Java, которому 23 мая этого года исполнилось тридцать лет, может, и не самый захватывающий язык, он остаётся одним из самых важных.
Путь Java начался 23 мая 1995 года, когда его выпустила компания Sun Microsystems. За прошедшее время благодаря удачному видению разработчиков и адаптивности он превратился из нишевого проекта для потребительской электроники в мощный фундамент энтерпрайз-, облачной и веб-разработки.
Хоть Java исполнилось тридцать, его история гораздо дольше. Корнями этот язык уходит в 1991 год, когда инженеры Sun Джеймс Гослинг, Майк Шеридан и Патрик Ноутон приступили к созданию языка для интерактивного телевидения и встроенных устройств. Этот проект назвали Green Project. Его цель заключалась не столько в написании нового языка, сколько в создании того, что бы мы сегодня назвали контроллером Интернета вещей. Ещё один разработчик Java Тим Линдхольм, описал его как «своего рода гибрид между КПК и универсальным пультом дистанционного управления».
https://habr.com/ru/articles/914970/
original https://www.zdnet.com/article/java-at-30-how-a-language-designed-for-a-failed-gadget-became-a-global-powerhouse/
👉@BookJava
Некоторые языки программирования, например Rust, Go и TypeScript, считаются крутыми. Другие, в том числе Cobol и Java, «скучны». Однако пусть Java, которому 23 мая этого года исполнилось тридцать лет, может, и не самый захватывающий язык, он остаётся одним из самых важных.
Путь Java начался 23 мая 1995 года, когда его выпустила компания Sun Microsystems. За прошедшее время благодаря удачному видению разработчиков и адаптивности он превратился из нишевого проекта для потребительской электроники в мощный фундамент энтерпрайз-, облачной и веб-разработки.
Хоть Java исполнилось тридцать, его история гораздо дольше. Корнями этот язык уходит в 1991 год, когда инженеры Sun Джеймс Гослинг, Майк Шеридан и Патрик Ноутон приступили к созданию языка для интерактивного телевидения и встроенных устройств. Этот проект назвали Green Project. Его цель заключалась не столько в написании нового языка, сколько в создании того, что бы мы сегодня назвали контроллером Интернета вещей. Ещё один разработчик Java Тим Линдхольм, описал его как «своего рода гибрид между КПК и универсальным пультом дистанционного управления».
https://habr.com/ru/articles/914970/
original https://www.zdnet.com/article/java-at-30-how-a-language-designed-for-a-failed-gadget-became-a-global-powerhouse/
👉@BookJava
👍4
На курсе «Java Developer. Professional» вы научитесь создавать современные Java-приложения, освоите Spring WebFlux и Kafka, а также разберётесь в работе JVM изнутри.
Пройдите тест, проверьте, достаточно ли у вас знаний для обучения на курсе:.
На курсе вас ждёт практическая работа с кодом, детальные разборы, ревью от экспертов и подходы, позволяющие писать эффективный и чистый код.
Начните свой путь к уровню Middle+ и используйте Java на 100%.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
Bulkhead — это паттерн из мира устойчивых систем, цель которого — изолировать сбои в одном компоненте, чтобы они не “затопили” всю систему. Сейчас я покажу вам несколько способов его реализации и подсвечу неочевидный момент при работе с любыми паттернами.
🧠 Концепция: представьте корабль с отсековыми переборками (bulkheads). Если вода просачивается в один отсек, остальные остаются сухими, и судно всё ещё может плыть. В мире Java/Spring это означает: ограничивать ресурсы (пулы потоков, соединения, очереди) для каждого сервиса/метода, чтобы при пике нагрузки или ошибках нагрузка не разошлась по всей системе.
📌 Способ 1: отдельные пул-экзекьюторы
В коде контроллера или сервиса указываем:
⚠️ Помните: если пул заполнится, новые задачи будут либо ждать (до исчерпания queueCapacity), либо бросать RejectionException. Настройте
📌 Способ 2: Resilience4j Bulkhead (Semaphore vs ThreadPool)
В сервисе:
💡 Если поставить
👉 Также есть аннотационный стиль:
или ThreadPool-вариант:
🧠 Неочевидный момент про паттерны в целом: внедрять Bulkhead “просто потому что модно” — плохо. Паттерн не заменяет мониторинг, трассировку или грамотную архитектуру. Он лишь ограничивает повреждения, но не показывает, где именно проблема. Если вы изолировали компонент в пул, а он всё равно падает, паттерн не скажет “почему”. Всегда сочетайте паттерны с метриками (Micrometer, Prometheus, Grafana) и логированием.
💡 Совет:
▫️Используйте отдельные пулы для медленных операций (например, внешних HTTP-вызовов) и отдельно для CPU-bound задач.
▫️На уровне базы данных тоже можно “бульхедом” выделять разные пулы соединений (например, HikariCP с разными конфигурациями) для тяжелых и легких запросов.
▫️При проектировании микросервисов отдавайте предпочтение Bulkhead на уровне отдельных сервисов: в Kubernetes это можно делать через limits/requests, Horizontal Pod Autoscaling и Circuit Breaker.
⚠️ Предупреждение: перебор с изоляцией приведет к недоиспользованию ресурсов. Если у вас слишком много мелких пулов, а нагрузка неравномерна, часть ресурсов простаивает. Поэтому сначала измерьте нагрузку, а потом разбивайте.
👉@BookJava
🧠 Концепция: представьте корабль с отсековыми переборками (bulkheads). Если вода просачивается в один отсек, остальные остаются сухими, и судно всё ещё может плыть. В мире Java/Spring это означает: ограничивать ресурсы (пулы потоков, соединения, очереди) для каждого сервиса/метода, чтобы при пике нагрузки или ошибках нагрузка не разошлась по всей системе.
📌 Способ 1: отдельные пул-экзекьюторы
@Configuration
public class BulkheadConfig {
@Bean("serviceAExecutor")
public ThreadPoolTaskExecutor serviceAExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("svcA-");
executor.initialize();
return executor;
}
}
В коде контроллера или сервиса указываем:
@Service
public class ServiceA {
@Autowired @Qualifier("serviceAExecutor")
private Executor executor;
public CompletableFuture<String> callExternal() {
return CompletableFuture.supplyAsync(() -> {
// долгий/ненадежный вызов
return externalClient.fetchData();
}, executor);
}
}
⚠️ Помните: если пул заполнится, новые задачи будут либо ждать (до исчерпания queueCapacity), либо бросать RejectionException. Настройте
RejectedExecutionHandler
по необходимости.📌 Способ 2: Resilience4j Bulkhead (Semaphore vs ThreadPool)
resilience4j.bulkhead.instances:
myServiceBulkhead:
maxConcurrentCalls: 5
maxWaitDuration: 100ms
В сервисе:
@Service
public class MyService {
private final Bulkhead bulkhead;
public MyService(BulkheadRegistry registry) {
this.bulkhead = registry.bulkhead("myServiceBulkhead");
}
public String process() {
return Bulkhead.decorateSupplier(bulkhead, () -> {
// защищенный вызов
return externalClient.process();
}).get();
}
}
💡 Если поставить
maxConcurrentCalls
слишком маленьким, часть запросов будет сразу отвергаться с BulkheadFullException
. Неочевидный момент: нужно мониторить реальную нагрузку и подбирать значения, а не копировать из гугла.👉 Также есть аннотационный стиль:
@Bulkhead(name = "myServiceBulkhead", type = Bulkhead.Type.SEMAPHORE)
public String annotatedProcess() { … }
или ThreadPool-вариант:
resilience4j.bulkhead.instances:
myThreadPoolBulkhead:
maxThreadPoolSize: 10
queueCapacity: 20
@Bulkhead(name = "myThreadPoolBulkhead", type = Bulkhead.Type.THREADPOOL)
public CompletionStage<String> asyncProcess() { … }
🧠 Неочевидный момент про паттерны в целом: внедрять Bulkhead “просто потому что модно” — плохо. Паттерн не заменяет мониторинг, трассировку или грамотную архитектуру. Он лишь ограничивает повреждения, но не показывает, где именно проблема. Если вы изолировали компонент в пул, а он всё равно падает, паттерн не скажет “почему”. Всегда сочетайте паттерны с метриками (Micrometer, Prometheus, Grafana) и логированием.
💡 Совет:
▫️Используйте отдельные пулы для медленных операций (например, внешних HTTP-вызовов) и отдельно для CPU-bound задач.
▫️На уровне базы данных тоже можно “бульхедом” выделять разные пулы соединений (например, HikariCP с разными конфигурациями) для тяжелых и легких запросов.
▫️При проектировании микросервисов отдавайте предпочтение Bulkhead на уровне отдельных сервисов: в Kubernetes это можно делать через limits/requests, Horizontal Pod Autoscaling и Circuit Breaker.
⚠️ Предупреждение: перебор с изоляцией приведет к недоиспользованию ресурсов. Если у вас слишком много мелких пулов, а нагрузка неравномерна, часть ресурсов простаивает. Поэтому сначала измерьте нагрузку, а потом разбивайте.
👉@BookJava
👍5❤3💩1
Как масштабировать машинные модели и работать с огромными объемами данных? Откройте для себя возможности Spark ML на открытом уроке от OTUS!
Spark ML — это мощный инструмент для масштабируемого машинного обучения, который позволяет обучать модели на больших данных, не переходя на специализированные ML-системы. Мы покажем, как интеграция с Spark SQL и DataFrame API упрощает ETL-подготовку данных и фичуризацию для реальных проектов.
Убедитесь, как Spark ML решает задачи отказоустойчивости и распределённых вычислений, позволяя вам легко строить промышленные ML-пайплайны.
Посетите открытый урок 11 июня в 20:00 МСК в преддверие старта курса «Spark Developer» и получите скидку на обучение: https://vk.cc/cMyLJ3
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Spark ML — это мощный инструмент для масштабируемого машинного обучения, который позволяет обучать модели на больших данных, не переходя на специализированные ML-системы. Мы покажем, как интеграция с Spark SQL и DataFrame API упрощает ETL-подготовку данных и фичуризацию для реальных проектов.
Убедитесь, как Spark ML решает задачи отказоустойчивости и распределённых вычислений, позволяя вам легко строить промышленные ML-пайплайны.
Посетите открытый урок 11 июня в 20:00 МСК в преддверие старта курса «Spark Developer» и получите скидку на обучение: https://vk.cc/cMyLJ3
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
❤3
Структурированное логирование в Spring Boot 3.5.5
Spring Boot 3.5.5 приносит улучшенное структурированное логирование.
Чтобы его включить, добавьте следующее в ваш
Это обеспечивает более чистые, структурированные логи, что делает их проще для разбора инструментами вроде ELK, Grafana или Datadog.
👉@BookJava
Spring Boot 3.5.5 приносит улучшенное структурированное логирование.
Чтобы его включить, добавьте следующее в ваш
application.yml
:Это обеспечивает более чистые, структурированные логи, что делает их проще для разбора инструментами вроде ELK, Grafana или Datadog.
👉@BookJava
❤6👍2
🎯 Java-хаки: динамический вывод с помощью printf()
Статья посвящена методу printf() в Java, который используется для создания форматированной строки вывода. В ней рассматривается синтаксис метода, различные спецификаторы формата (например, %d, %f, %s и т.д.) и то, как с их помощью управлять отображением чисел, строк и других типов данных в консоли.
Приведены примеры использования
https://springframework.guru/java-output-printf-method/
👉@BookJava
Статья посвящена методу printf() в Java, который используется для создания форматированной строки вывода. В ней рассматривается синтаксис метода, различные спецификаторы формата (например, %d, %f, %s и т.д.) и то, как с их помощью управлять отображением чисел, строк и других типов данных в консоли.
Приведены примеры использования
System.out.printf()
с пояснениями по флагам, ширинe и точности форматирования, а также показано, как легко создавать динамический и читаемый вывод в приложениях на Java.https://springframework.guru/java-output-printf-method/
👉@BookJava
👍1
📚 Эффективное сжатие текста: код Хаффмана в действии
Приглашаем на открытый урок.
🗓 11 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Алгоритмы и структуры данных».
На этом вебинаре мы продолжим разработку архиватора, реализовав код Хаффмана.
✔️ Рассмотрим, как построить дерево кодов, где частота появления символов определяет их битовое представление.
✔️ Интегрируем алгоритм в наш архиватор и проведем сравнительное тестирование с RLE.
✔️ Увидим, как эффективно работает код Хаффмана на текстовых файлах и других типах данных.
Отличная возможность изучить продвинутые древовидные структуры данных на практическом примере.
Развивайте алгоритмическое мышление, увеличивайте производительность программ.
🎁 Всем участникам вебинара дарим промокод, который дает скидку на обучение - Algo5
👉 Регистрация на вебинар: https://vk.cc/cMzyUv
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Приглашаем на открытый урок.
🗓 11 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Алгоритмы и структуры данных».
На этом вебинаре мы продолжим разработку архиватора, реализовав код Хаффмана.
Отличная возможность изучить продвинутые древовидные структуры данных на практическом примере.
Развивайте алгоритмическое мышление, увеличивайте производительность программ.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🚀 Spring WebFlux с Server-Sent Events 🚀
Улучшите свои приложения в режиме реального времени с помощью #SpringWebFlux и Server-Sent Events! 🔥
👉@BookJava
Улучшите свои приложения в режиме реального времени с помощью #SpringWebFlux и Server-Sent Events! 🔥
👉@BookJava
❤5👍2
👍6
⚡️ Быстрые альтернативы HashMap: EnumMap, массивы и примитивные коллекции
🧠 EnumMap вместо HashMap (enum-ключи)
📌
⚠️ Работает только для enum-ключей.
🧠 Прямой массив для плотных int-ключей
📌 Используйте массив вместо Map, если ключи — диапазон
💡 O(1), без коллизий и аллокаций объектов.
⚠️ Память линейно зависит от MAX.
🧠 Специализированные коллекции для примитивов
📌 Библиотеки fastutil, HPPC, Trove и др.
💡 Избегаете boxing/unboxing и получаете быстрее операции.
🧠 Switch-expression / tableswitch
📌 Для фиксированного набора целых или enum-ключей генерируйте
💡 JIT компилирует
💡 Выбирайте стратегию под конкретную задачу:
- EnumMap — enum-ключи
- Массив — плотные int-диапазоны
- fastutil/HPPC — примитивы с большим диапазоном
- Switch — фиксированный набор значений
👉@BookJava
🧠 EnumMap вместо HashMap (enum-ключи)
📌
EnumMap<K, V>
хранит данные в массиве → нет хеширования и boxing’а.
EnumMap<Status, String> map = new EnumMap<>(Status.class);
map.put(Status.STARTED, "Запущен");
String status = map.get(Status.STARTED);
⚠️ Работает только для enum-ключей.
🧠 Прямой массив для плотных int-ключей
📌 Используйте массив вместо Map, если ключи — диапазон
[0…MAX]
и известны заранее.
int MAX = 1000;
var cache = new String[MAX + 1];
cache[42] = "ответ";
String result = cache[42];
💡 O(1), без коллизий и аллокаций объектов.
⚠️ Память линейно зависит от MAX.
🧠 Специализированные коллекции для примитивов
📌 Библиотеки fastutil, HPPC, Trove и др.
var fastMap = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<String>();
fastMap.put(42, "ответ");
String res = fastMap.get(42);
💡 Избегаете boxing/unboxing и получаете быстрее операции.
🧠 Switch-expression / tableswitch
📌 Для фиксированного набора целых или enum-ключей генерируйте
switch
, а не Map.
String handle(int code) {
return switch (code) {
case 100 -> "OK";
case 200 -> "Created";
default -> "Other";
};
}
💡 JIT компилирует
switch
в tableswitch
или lookupswitch
— молниеносно.💡 Выбирайте стратегию под конкретную задачу:
- EnumMap — enum-ключи
- Массив — плотные int-диапазоны
- fastutil/HPPC — примитивы с большим диапазоном
- Switch — фиксированный набор значений
👉@BookJava
👍5❤1
📌 Stream.toList() vs Collectors.toList() — безопасная замена?
🧠 В Java 16+ появился метод
Теперь можно укоротить до:
💡 Главные отличия:
1️⃣ Неизменяемость
Если нужен изменяемый список, продолжайте использовать
2️⃣ Null-элементы
3️⃣ Спецификация
⚠️ Если вам важна мутабельность или поддержка null — не меняйте на
✅ Если же нужен чистый readonly-список и вы уверены в отсутствии
Я перехожу на
👉@BookJava
🧠 В Java 16+ появился метод
Stream.toList()
, который собирает элементы потока в список. Раньше мы писали:
List<String> list = stream.collect(Collectors.toList());
Теперь можно укоротить до:
List<String> list = stream.toList();
💡 Главные отличия:
1️⃣ Неизменяемость
toList()
возвращает unmodifiable List
— любые add()/remove()
вылетят UnsupportedOperationException
.Если нужен изменяемый список, продолжайте использовать
collect(Collectors.toList())
или
stream.collect(Collectors.toCollection(ArrayList::new));
2️⃣ Null-элементы
toList()
не допускает null
и бросит NPE при встрече null
в потоке. Collectors.toList()
сохранит null
без ошибок.3️⃣ Спецификация
Stream.toList()
гарантированно создаёт новый список с точным размером, а Collectors.toList()
лишь «может» вернуть любой List
(часто ArrayList
, но без чётких гарантий).⚠️ Если вам важна мутабельность или поддержка null — не меняйте на
toList()
.✅ Если же нужен чистый readonly-список и вы уверены в отсутствии
null
— смело переходите на toList()
для более лаконичного и потенциально более эффективного кода.Я перехожу на
toList()
везде, где нужен только чтение — получилось короче и понятнее.👉@BookJava
👍9
⁉️ Монолит или микросервисы? Руководство для архитекторов, которые ценят свои нервы
Приглашаем на открытый урок.
🗓 17 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Software Architect».
📌 Что будет на вебинаре:
✔️ Как не попасть в ловушку “модных” микросервисов;
✔️ Разбор признаков, что пора выходить из монолита;
✔️ Архитектурные паттерны для перехода к микросервисам (Strangler Fig, BFF, Self-contained systems);
✔️ Организационные и технические риски — что точно пойдёт не так и как это предсказать;
✔️ Роль DevOps, CI/CD и мониторинга в выборе архитектуры.
👥 Для кого этот вебинар:
- Разработчиков Backend и FullStack, участвующих в архитектурных решениях;
- Архитекторов ПО, которые планируют масштабирование приложений;
- Тимлидов и DevOps-инженеров, выстраивающих процесс разработки и доставки;
- Технических менеджеров, выбирающих стратегию развития продукта.
🎯 После вебинара вы:
- Получите пошаговое руководство по выбору архитектуры под ваш проект;
- Научитесь оценивать реальные риски и стоимость микросервисов;
- Поймёте, как внедрять архитектурные изменения без сбоев и хаоса;
- Увидите, как принимать взвешенные архитектурные решения, сохраняя технический контроль и производительность команды.
💡 Идеальный вебинар для тех, кто хочет перестать "архитектурить на ощущениях" и начать действовать стратегически.
🎁 Всем участникам вебинара дарим промокод, который дает скидку на обучение - SoftwareArc_06
👉 Регистрация на вебинар: https://vk.cc/cMHSzz
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Приглашаем на открытый урок.
🗓 17 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Software Architect».
📌 Что будет на вебинаре:
👥 Для кого этот вебинар:
- Разработчиков Backend и FullStack, участвующих в архитектурных решениях;
- Архитекторов ПО, которые планируют масштабирование приложений;
- Тимлидов и DevOps-инженеров, выстраивающих процесс разработки и доставки;
- Технических менеджеров, выбирающих стратегию развития продукта.
🎯 После вебинара вы:
- Получите пошаговое руководство по выбору архитектуры под ваш проект;
- Научитесь оценивать реальные риски и стоимость микросервисов;
- Поймёте, как внедрять архитектурные изменения без сбоев и хаоса;
- Увидите, как принимать взвешенные архитектурные решения, сохраняя технический контроль и производительность команды.
💡 Идеальный вебинар для тех, кто хочет перестать "архитектурить на ощущениях" и начать действовать стратегически.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👎1
📌 CRaC (Coordinated Restore at Checkpoint) — горячая JVM-фишка для сверхбыстрого cold-start: сохраняем состояние приложения после инициализации и моментально «восстанавливаем» при рестарте.
🧠 Как это работает
1. JVM создаёт снимок (checkpoint) всего heap- и native-состояния сразу после bootstrap и bean-инициализации.
2. При рестарте JVM грузит этот снимок вместо полной загрузки классов и прогрева JIT.
💡 Подключение в Java 21+
1. Включите экспериментальный модуль:
2. Реализуйте
3. Сборка и запуск:
⚠️ Ограничения и нюансы
* Не все native-библиотеки безопасны для снапшота.
* Тяжёлые background-потоки: до checkpoint лучше останавливать.
* Проверяйте на staging-окружении — subtle bugs могут всплыть только после restore.
📌 Зачем это нужно?
* 🚀 Ускоренный cold-start для Spring Boot 3+ сервисов (лучшая DevOps-интеграция в контейнерах и serverless).
* 💰 Экономия ресурсов в автоскейлируемых кластерах.
Простой CRaC-proof-of-concept позволит вам измерить прирост старта ваших микросервисов уже сегодня!
👉@BookJava
🧠 Как это работает
1. JVM создаёт снимок (checkpoint) всего heap- и native-состояния сразу после bootstrap и bean-инициализации.
2. При рестарте JVM грузит этот снимок вместо полной загрузки классов и прогрева JIT.
💡 Подключение в Java 21+
1. Включите экспериментальный модуль:
--add-modules jdk.crac
--enable-preview
2. Реализуйте
CheckpointListener
для чистки и восстановления ресурсов:
import jdk.crac.Core;
import jdk.crac.Control;
import jdk.crac.CheckpointListener;
import jdk.crac.Context;
import org.springframework.stereotype.Component;
@Component
public class CracHandler implements CheckpointListener {
@Override
public void beforeCheckpoint(Context<?> ctx) {
// 📌 Закрываем пулы, Flush в БД, отписываемся от очередей
}
@Override
public void afterRestore(Context<?> ctx) {
// 💡 Реинициализируем пулы, повторная регистрация listeners
}
}
// Регистрация слушателя
Core.getGlobalContext().register(new CracHandler());
3. Сборка и запуск:
# Сохраняем checkpoint
java \
--add-modules jdk.crac \
--enable-preview \
-XX:CRaCCheckpointToDir=crac-checkpoint \
-jar app.jar
# Восстанавливаем из него
java \
--add-modules jdk.crac \
--enable-preview \
-XX:CRaCRestoreFrom=crac-checkpoint \
-jar app.jar
⚠️ Ограничения и нюансы
* Не все native-библиотеки безопасны для снапшота.
* Тяжёлые background-потоки: до checkpoint лучше останавливать.
* Проверяйте на staging-окружении — subtle bugs могут всплыть только после restore.
📌 Зачем это нужно?
* 🚀 Ускоренный cold-start для Spring Boot 3+ сервисов (лучшая DevOps-интеграция в контейнерах и serverless).
* 💰 Экономия ресурсов в автоскейлируемых кластерах.
Простой CRaC-proof-of-concept позволит вам измерить прирост старта ваших микросервисов уже сегодня!
👉@BookJava
👍5❤1
👩💻 JPQL: как писать запросы, которые не сломают Hibernate
Узнайте, как писать JPQL-запросы, которые ускорят Hibernate в 5 раз, избегая критических ошибок, тормозящих 80% проектов!
Приглашаем на открытый урок
🗓 19 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Professional».
🎯 О чём поговорим:
✔️ - JPQL vs SQL: почему ваши запросы ломают Hibernate и как их переписать так, чтобы БД не «умирала» под нагрузкой.
✔️ Тайные ловушки: антипаттерны JPQL, генерирующие N+1 SELECT и тормозящие приложение, и методы их поиска в коде.
✔️ Оптимизация на максимум: как использовать JOIN FETCH, подзапросы и кэширование в JPQL для мгновенного ускорения Hibernate.
👥 Кому будет интересно:
Java-разработчикам, использующим Hibernate, системным архитекторам и инженерам по оптимизации производительности.
💡В результате урока вы:
Научитесь писать эффективные JPQL-запросы, избегать распространённых ошибок и значительно ускорять работу Hibernate-приложений.
🎁 Дарим промокод, который дает скидку на обучение - JAVA_06
🔗 Ссылка на регистрацию: https://vk.cc/cMKvog
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Узнайте, как писать JPQL-запросы, которые ускорят Hibernate в 5 раз, избегая критических ошибок, тормозящих 80% проектов!
Приглашаем на открытый урок
🗓 19 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Professional».
🎯 О чём поговорим:
👥 Кому будет интересно:
Java-разработчикам, использующим Hibernate, системным архитекторам и инженерам по оптимизации производительности.
💡В результате урока вы:
Научитесь писать эффективные JPQL-запросы, избегать распространённых ошибок и значительно ускорять работу Hibernate-приложений.
🔗 Ссылка на регистрацию: https://vk.cc/cMKvog
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM