10986
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP
Открыт набор в Т-Академию
Пройдите бесплатное обучение по аналитике или разработке на задачах, похожих на те, с которыми работают специалисты в крупных ИТ-компаниях.
В Т-Академии студенты каждую неделю выполняют практические задания и развивают собственный pet-проект. Приглашенные наставники из Т-Банка помогут прокачаться в одном из треков — разработке (backend, frontend, mobile) или в продуктовой аналитике.
Подойдет тем, кто уже знает базу, но не понимает, как применить ее на практике.
Учеба онлайн, можно совмещать с вузом или работой.
Помимо хардов — прокачка софт-скиллов, тренировочные интервью, мастер-классы и встречи в городах, где есть ИТ-хабы Т‑Банка.
У лучших будет шанс продолжить карьеру в команде.
Подать заявку можно до 31 июля
Проверка на null с помощью OptionalOptional помогает избежать NullPointerExceptions.
String name = "Alice";
Optional<String> maybeName = Optional.ofNullable(name);
System.out.println(maybeName.orElse("Nobody")); // Output: Alice
🚀 7 самых полезных методов Stream API в Java 21
Работаешь с коллекциями в Java? Тогда Stream API — твой лучший друг. В Java 21 он стал ещё удобнее. Вот краткая шпаргалка по самым нужным методам — с понятными примерами 👇
🔹 1. filter(Predicate)
📌 Фильтрует элементы по условию.
🧠 Пример: оставить только чётные числа:
List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.toList();
List<String> upperCaseNames = names.stream()
.map(String::toUpperCase)
.toList();
List<String> words = nestedLists.stream()
.flatMap(List::stream)
.toList();
Set<String> uniqueNames = names.stream()
.collect(Collectors.toSet());
names.stream().forEach(System.out::println);
int sum = numbers.stream()
.reduce(0, Integer::sum);
List<Integer> lessThanTen = numbers.stream()
.takeWhile(n -> n < 10)
.toList();
collect(...) используй toList() и toSet() — код станет чище, а производительность выше.
👩💻🎯 Юнитесты на Java: как новичку поймать баги за 5 Секунд?
Приглашаем на открытый урок.
🗓 25 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java-разработчик».
🦾 Тестирование — суперсила разработчика. Научитесь писать код, который проверяет сам себя, экономит часы на отладке и делает ваши приложения неуязвимыми.
О чём поговорим:
✔️ Что такое Unit-тесты? Для чего они нужны, даже если «код и так работает».
✔️ JUnit 5 для новичков: как установить и написать первый тест.
✔️ Тестирование = Дзен-кодинг: как тесты помогают понять свой код лучше вас самих.
✔️ Ловушки и лайфхаки: что делать, если тесты падают?
Кому будет интересно:
Начинающим Java-разработчикам, студентам и всем, кто хочет перестать бояться слов «тестирование» и «баги».
В результате вебинара вы:
Создадите свой первый тест на Java, поймёте, как тестировать методы с исключениями, и начнёте писать код, которым можно гордиться.
🔗 Ссылка на регистрацию: https://vk.cc/cN4MxX
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🧠 Spring Boot + MapStruct: как избежать null при обновлении сущности
При обновлении сущностей через MapStruct бывает типичная проблема: маппер затирает уже существующие поля null'ами, если они не переданы во входном DTO. Это может легко привести к потере данных. Покажу, как решить это изящно.
Допустим, у нас есть:
public class UserDto {
private String name;
private String email;
}
@Entity
public class User {
private String name;
private String email;
}
@MappingTarget, то:
@MappingTarget User user, UserDto dto
email в dto затирает значение в user.
@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface UserMapper {
void update(@MappingTarget User user, UserDto dto);
}
NullValuePropertyMappingStrategy.IGNORE говорит MapStruct: не трогай те поля, которые в DTO пришли как null.Optional и не для примитивов. Там потребуется другая стратегия — например, обёртки или @Condition.
Совет 💡
Если вы хотите получить сообщение о первопричине, вы можете легко и безопасно получить его с помощью Apache Commons ExceptionUtils. Методы getRootCauseMessage(Exception ex) выдают сообщение в виде {ClassNameWithoutPackage} {ThrowableMessage}
👉@BookJava
🧠 Трюк с @EventListener в Spring Boot — неочевидная ловушка
Когда ты используешь @EventListener для обработки событий в Spring, ты можешь попасть в баг, который очень сложно отловить в бою — пропущенные события.
📌 Пример:
@Component
public class MyListener {
@EventListener
public void on(MyEvent event) {
// логика
}
}
MyListener бин ещё не проинициализирован, а событие уже публикуется (ApplicationEventPublisher#publishEvent), то метод on просто не будет вызван. Spring не будет "накапливать" события для будущих слушателей.@PostConstruct или в CommandLineRunner, а слушатель находится в другом бине, который ещё не загружен.@DependsOn.ApplicationReadyEvent:
@Component
public class Publisher {
private final ApplicationEventPublisher publisher;
public Publisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
publisher.publishEvent(new MyEvent(this));
}
}
ApplicationRunner или InitializingBean, где порядок можно контролировать проще.
💡 Почему в Set.of() в Java нельзя добавить дубликаты и null?
Когда используешь Set.of(...), можно столкнуться с двумя неожиданностями:
1. ❌ Нельзя добавлять дубликаты
2. ❌ Нельзя добавлять null
Разбираемся, почему так:
🔐 Set.of(...) — это immutable Set
Метод Set.of(...), добавленный в Java 9, создаёт неизменяемое множество. Это значит:
* После создания ты не можешь изменить его (добавить, удалить элемент).
* Все элементы внутри должны быть уникальны и не должны быть null.
📛 Почему нельзя дубликаты?
Потому что Set по определению — это коллекция уникальных элементов.
А Set.of(...) бросает IllegalArgumentException, сразу во время создания, если переданы дубликаты:
Set.of("a", "b", "a"); // 💥 Бросит исключение!
null?Set.of(...) не принимает null, потому что он реализован через внутренние immutable структуры, которые не допускают null`-значений. При попытке добавить `null получишь NullPointerException.
Set.of("a", null); // 💥 NullPointerException
null может вести к неочевидным багам и плохо сочетается с концепцией неизменяемых коллекций.Set, который принимает null и дубликаты фильтрует сам? Используй HashSet:
Set<String> set = new HashSet<>();
set.add(null); // ✅ Можно
📚 Продвинутые методы архивации: LZ77/78
Приглашаем на открытый урок.
🗓 25 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Алгоритмы и структуры данных».
✔️ На этом вебинаре мы завершим создание архиватора, добавив алгоритм LZ77/78. Разберем принцип словарного сжатия, механизм поиска повторяющихся последовательностей и формат их кодирования.
✔️ Имплементируем выбранный алгоритм и проведем финальное сравнение всех трех методов сжатия (RLE, Huffman, LZ77/78). Определим, какие алгоритмы лучше работают для различных типов файлов и почему.
Завершающее практическое занятие для тех, кто хочет освоить продвинутые алгоритмы и увидеть их применение в реальном проекте.
🎁 Всем участникам вебинара дарим промокод, который дает скидку на обучение - Algo5
👉 Регистрация на вебинар: https://vk.cc/cMXtZN
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🧠 Коллекторы и toList() в Java 16+: можно ли заменить collect(Collectors.toList()) на просто .toList()?
Да, но с нюансами.
📌 Короткий ответ:
Если ты используешь Java 16+, можешь заменить:
List<String> list = stream.collect(Collectors.toList());
List<String> list = stream.toList();
.toList() возвращает немодифицируемый список (immutable).Collectors.toList() возвращает modifiable ArrayList.
var list1 = List.of("a", "b");
var list2 = list1.stream().toList();
list2.add("c"); // 💥 UnsupportedOperationException
var list3 = list1.stream().collect(Collectors.toList());
list3.add("c"); // ✅ OK
Collectors.toList() — это ArrayList (или его сабкласс)..toList() — это неопределённый тип внутри JDK (часто List.of под капотом).
if (list instanceof ArrayList) ...
.toList() оптимизирован для параллельных стримов: может работать быстрее, но также может повлиять на порядок, если ты этого явно не контролируешь.ArrayList).Заменяйcollect(Collectors.toList())на.toList(), только если тебе действительно не нужен изменяемый список. Это безопасно при соблюдении условий, но может привести к неожиданным багам в тестах и проде, если забыть про неизменяемость.
🧠 Record (Java 16+) + pattern matching для instanceof (Java 14+) в Java 17+ позволяют писать лаконичный и безопасный код:
📌 Запись DTO с валидацией через компактный конструктор:
public record User(String name, String email) {
public User {
Objects.requireNonNull(name, "name не должен быть null");
if (!email.contains("@")) {
throw new IllegalArgumentException("Неверный email: " + email);
}
}
}
toString(), equals(), hashCode() без лишнего кода.
Object obj = …;
if (obj instanceof User u) {
System.out.println("Привет, " + u.name());
}
public record Team(String name, List<String> members) {
public Team {
members = List.copyOf(members);
}
}
members нельзя изменить извне.public record X(List<String> list) без копирования — рискуете нарушить неизменяемость!
👩💻 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
⁉️ Монолит или микросервисы? Руководство для архитекторов, которые ценят свои нервы
Приглашаем на открытый урок.
🗓 17 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Software Architect».
📌 Что будет на вебинаре:
✔️ Как не попасть в ловушку “модных” микросервисов;
✔️ Разбор признаков, что пора выходить из монолита;
✔️ Архитектурные паттерны для перехода к микросервисам (Strangler Fig, BFF, Self-contained systems);
✔️ Организационные и технические риски — что точно пойдёт не так и как это предсказать;
✔️ Роль DevOps, CI/CD и мониторинга в выборе архитектуры.
👥 Для кого этот вебинар:
- Разработчиков Backend и FullStack, участвующих в архитектурных решениях;
- Архитекторов ПО, которые планируют масштабирование приложений;
- Тимлидов и DevOps-инженеров, выстраивающих процесс разработки и доставки;
- Технических менеджеров, выбирающих стратегию развития продукта.
🎯 После вебинара вы:
- Получите пошаговое руководство по выбору архитектуры под ваш проект;
- Научитесь оценивать реальные риски и стоимость микросервисов;
- Поймёте, как внедрять архитектурные изменения без сбоев и хаоса;
- Увидите, как принимать взвешенные архитектурные решения, сохраняя технический контроль и производительность команды.
💡 Идеальный вебинар для тех, кто хочет перестать "архитектурить на ощущениях" и начать действовать стратегически.
🎁 Всем участникам вебинара дарим промокод, который дает скидку на обучение - SoftwareArc_06
👉 Регистрация на вебинар: https://vk.cc/cMHSzz
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
⚡️ Быстрые альтернативы HashMap: EnumMap, массивы и примитивные коллекции
🧠 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);
[0…MAX] и известны заранее.
int MAX = 1000;
var cache = new String[MAX + 1];
cache[42] = "ответ";
String result = cache[42];
var fastMap = new it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap<String>();
fastMap.put(42, "ответ");
String res = fastMap.get(42);
switch, а не Map.
String handle(int code) {
return switch (code) {
case 100 -> "OK";
case 200 -> "Created";
default -> "Other";
};
}
switch в tableswitch или lookupswitch — молниеносно.
🚀 Spring WebFlux с Server-Sent Events 🚀
Улучшите свои приложения в режиме реального времени с помощью #SpringWebFlux и Server-Sent Events! 🔥
👉@BookJava
🔍 Enumeration vs Iterator в Java
Java-программисты часто сталкиваются с двумя интерфейсами для перебора коллекций: устаревшим Enumeration и современным Iterator. Разберём ключевые отличия:
1️⃣ Происхождение
* Enumeration появился в Java 1.0 и используется в старых классах (Vector, Hashtable).
* Iterator введён в Java 1.2 вместе с коллекциями из пакета java.util (List, Set и т.д.).
2️⃣ Методы и возможности
* Enumeration предоставляет методы hasMoreElements() для проверки и nextElement() для получения следующего элемента, но не умеет удалять элементы во время итерации.
* Iterator использует hasNext() и next(), а также имеет метод remove() для безопасного удаления элементов прямо во время обхода.
3️⃣ Fail-fast поведение
* Iterator отслеживает изменения коллекции извне и при обнаружении бросает ConcurrentModificationException.
* Enumeration такого механизма не имеет — внешние модификации могут приводить к непредсказуемым результатам.
4️⃣ Поддержка дженериков
* Enumeration не типобезопасен (до Java 1.5), что требовало кастов.
* Iterator<E> полностью интегрирован с дженериками, что позволяет избежать ClassCastException.
5️⃣ Когда использовать
* Iterator — выбор по умолчанию для всех современных коллекций: гибкость, безопасность и поддержка удаления.
* Enumeration — только при взаимодействии с legacy-API (Vector, Hashtable и др.).
💡 Вывод: выбирайте Iterator — он более универсален, безопасен и дружелюбен к дженерикам. Enumeration сохранён в языке лишь ради обратной совместимости.
👉@BookJava
Как контролировать и управлять приложениями на Spring Boot без лишней головной боли?
На открытом вебинаре «Spring Boot Actuator: основы мониторинга и управления приложением» 25 июня в 20:00 МСК мы разберём:
- Для чего нужен Spring Boot Actuator.
- Как настроить и использовать метрики для контроля приложений.
- Как избежать проблем с производительностью на ранних этапах разработки.
Представьте, что вы с лёгкостью настраиваете мониторинг, отслеживаете метрики и эффективно управляете приложениями без перерывов в работе. Это станет возможным, если освоить Spring Boot Actuator.
Открытый урок проходит в преддверии старта курса «Разработчик на Spring Framework» — все участники получат скидку на обучение.
Регистрируйтесь прямо сейчас: https://vk.cc/cN4MSC
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
💡 Совет Java
✅ Заменяем и переворачиваем последнее слово в строке — без использования StringBuilder!
Когда-нибудь задумывался, как в Java перевернуть только последнее слово в предложении и вставить его обратно? 🤔
Вот лаконичное решение на чистом Java, без использования StringBuilder.
💡 Отлично подойдёт новичкам, чтобы лучше понять:
1. Логику реверса строки 🔁
2. Работу с массивами и циклами 🧩
3. Почему важно избегать изменяемых классов, вроде StringBuilder, когда тренируешь основы 💪
👉@BookJava
Создание REST API с использованием Spring WebFlux и Security
00:00:00 Введение
00:00:20 Создание проекта
00:11:36 Создание миграций БД
00:15:40 Создание базовых классов
00:23:20 Реализация логики генерации JWT токена
00:46:30 Реализация логики валидации JWT токена
00:53:05 Построения цепочки аутентификации
01:04:22 Финальная конфигурация с использованием SecurityWebFilterChain
01:12:11 Реализация REST контроллеров
01:23:15 Проверка REST API средствами Postman
01:24:21 Добавление и конфигурация обработчика ошибок
01:25:40 Заключение
Ссылка на Github репозиторий https://github.com/proselytear/webfluxsecurity
источник
👉@BookJava
Когда системы не хотят «дружить» между собой — начинается головная боль.😫
Особенно если речь идет о масштабировании и автоматизации процессов. Как избежать лишнего кода, сэкономить время и силы, при этом интегрировать внешние системы с Apache Kafka?
Ответ — Kafka Connect.
Записывайтесь на открытый вебинар, где мы разберем, как решить типичные проблемы интеграции и масштабирования.
Что будет на вебинаре:
✒️Основы Kafka Connect: Архитектура и принципы работы, коннекторы
✒️Практическая реализация: Настройка и запуск коннекторов для интеграции с базами данных и файловыми системами
✒️Ошибки и их решение: Как эффективно отлаживать и масштабировать Kafka Connect
23 июня в 19:00 (МСК) — Бесплатно!
Спикер: Валентин Шилин — Старший программист и аналитик данных в Deutsche Telekom IT GmbH
Дарим чек-лист по установке Kafka Connect при регистрации на вебинар!
Присоединяйтесь, если хотите научиться упрощать сложные задачи и увеличивать надежность своих систем: https://tglink.io/88d34f764ba1
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. erid: 2W5zFH5vcGg
🚀 Подборка Telegram каналов для программистов
Системное администрирование, DevOps 📌
/channel/bash_srv Bash Советы
/channel/win_sysadmin Системный Администратор Windows
/channel/sysadmin_girl Девочка Сисадмин
/channel/srv_admin_linux Админские угодья
/channel/linux_srv Типичный Сисадмин
/channel/devopslib Библиотека девопса | DevOps, SRE, Sysadmin
/channel/linux_odmin Linux: Системный администратор
/channel/devops_star DevOps Star (Звезда Девопса)
/channel/i_linux Системный администратор
/channel/linuxchmod Linux
/channel/sys_adminos Системный Администратор
/channel/tipsysdmin Типичный Сисадмин (фото железа, было/стало)
/channel/sysadminof Книги для админов, полезные материалы
/channel/i_odmin Все для системного администратора
/channel/i_odmin_book Библиотека Системного Администратора
/channel/i_odmin_chat Чат системных администраторов
/channel/i_DevOps DevOps: Пишем о Docker, Kubernetes и др.
/channel/sysadminoff Новости Линукс Linux
1C разработка 📌
/channel/odin1C_rus Cтатьи, курсы, советы, шаблоны кода 1С
/channel/DevLab1C 1С:Предприятие 8
/channel/razrab_1C 1C Разработчик
/channel/buh1C_prog 1C Программист | Бухгалтерия и Учёт
/channel/rabota1C_rus Вакансии для программистов 1С
Программирование C++📌
/channel/cpp_lib Библиотека C/C++ разработчика
/channel/cpp_knigi Книги для программистов C/C++
/channel/cpp_geek Учим C/C++ на примерах
Программирование Python 📌
/channel/pythonofff Python академия.
/channel/BookPython Библиотека Python разработчика
/channel/python_real Python подборки на русском и английском
/channel/python_360 Книги по Python
Java разработка 📌
/channel/BookJava Библиотека Java разработчика
/channel/java_360 Книги по Java Rus
/channel/java_geek Учим Java на примерах
GitHub Сообщество 📌
/channel/Githublib Интересное из GitHub
Базы данных (Data Base) 📌
/channel/database_info Все про базы данных
Мобильная разработка: iOS, Android 📌
/channel/developer_mobila Мобильная разработка
/channel/kotlin_lib Подборки полезного материала по Kotlin
Фронтенд разработка 📌
/channel/frontend_1 Подборки для frontend разработчиков
/channel/frontend_sovet Frontend советы, примеры и практика!
/channel/React_lib Подборки по React js и все что с ним связано
Разработка игр 📌
/channel/game_devv Все о разработке игр
Библиотеки 📌
/channel/book_for_dev Книги для программистов Rus
/channel/programmist_of Книги по программированию
/channel/proglb Библиотека программиста
/channel/bfbook Книги для программистов
БигДата, машинное обучение 📌
/channel/bigdata_1 Big Data, Machine Learning
Программирование 📌
/channel/bookflow Лекции, видеоуроки, доклады с IT конференций
/channel/rust_lib Полезный контент по программированию на Rust
/channel/golang_lib Библиотека Go (Golang) разработчика
/channel/itmozg Программисты, дизайнеры, новости из мира IT
/channel/php_lib Библиотека PHP программиста 👨🏼💻👩💻
/channel/nodejs_lib Подборки по Node js и все что с ним связано
/channel/ruby_lib Библиотека Ruby программиста
/channel/lifeproger Жизнь программиста. Авторский канал.
QA, тестирование 📌
/channel/testlab_qa Библиотека тестировщика
Шутки программистов 📌
/channel/itumor Шутки программистов
Защита, взлом, безопасность 📌
/channel/thehaking Канал о кибербезопасности
/channel/xakep_2 Хакер Free
Книги, статьи для дизайнеров 📌
/channel/ux_web Статьи, книги для дизайнеров
Математика 📌
/channel/Pomatematike Канал по математике
/channel/phis_mat Обучающие видео, книги по Физике и Математике
/channel/matgeoru Математика | Геометрия | Логика
Excel лайфхак📌
/channel/Excel_lifehack
/channel/mir_teh Мир технологий (Technology World)
Вакансии 📌
/channel/sysadmin_rabota Системный Администратор
/channel/progjob Вакансии в IT
🤯 🤯 🤯 Параллелизм в многопоточном Java-коде создаёт новые проблемы в тестировании, а баги остаются незамеченными?
⚡️ Приглашаем на открытый вебинар «Юнит тесты для многопоточного кода»
24 июня в 20:00 МСК.
На вебинаре мы разберём:
✔️ Как обнаружить гонки, дедлоки и нестабильность в многопоточном коде.
✔️ Как использовать argumentCaptor и spy для проверки взаимодействия потоков.
✔️ Эмуляцию задержек и таймингов с помощью AdditionalAnswers.
🦾 После урока вы будете уверенно писать стабильные unit-тесты для многопоточного кода, выявлять скрытые баги и улучшать качество тестирования.
Открытый урок проходит в преддверии старта курса «Java Developer. Advanced».
Все участники получат скидку на обучение.
🔗 Регистрируйтесь прямо сейчас: https://vk.cc/cMZNzb
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Вопросы-ответы собеседования
Можно ли создать экземпляр абстрактного класса?
Что такое интерфейс?
Как вызвать нестатический метод в статическом?
Чем отличаются параметры от аргументов в методе?
Что такое конструктор? Как его создать и вызвать?
Что такое параметризованный конструктор?
Что такое конструктор по умолчанию?
Что такое приватный конструктор? Зачем он закрытый?
Что такое статическая переменная? Как работает static поле?
Что такое статический метод? Как вызвать static метод?
источник
👉@BookJava
🧠 Осторожно с @Transactional на private-методах!
Очень частый анти-паттерн, который легко упустить 👇@Service
public class UserService {
@Transactional
private void saveUser(User user) {
userRepository.save(user);
}
public void create() {
saveUser(new User());
}
}
Кажется, всё ок. Но ❌ транзакция НЕ работает.
📌 Почему?
Spring AOP использует прокси, а прокси не “видит” вызовы private-методов внутри класса. Такие вызовы происходят напрямую, мимо прокси-обёртки — и аннотация @Transactional просто игнорируется.
💡 Решение:
1. Сделай метод public и вызывай его извне (или из другого бина).
2. Или выдели этот метод в отдельный бин-сервис.
Пример:@Service
public class UserTransactionalHelper {
@Transactional
public void saveUser(User user) {
userRepository.save(user);
}
}
И в UserService:public void create() {
helper.saveUser(new User());
}
⚠️ Так же не работают protected, private, final, static, и @PostConstruct-методы.
Нужно помнить: Spring AOP = прокси, а значит, работают только публичные методы, вызываемые ИЗВНЕ.
👉@BookJava
VK Weekend Offer: отправьте заявку, пройдите интервью и получите офер!
28–29 июня VK проведёт Weekend Offer для бэкендеров с опытом от трёх лет. Участников со знанием Java, Go, Python или C++ ждут технические собеседования, знакомство с продуктами и, если всё сложится, офер уже в конце выходных.
Ребята много лет создают облачные решения, системы рекомендаций и поисковые движки — всё с миллионами пользователей в проде — и сейчас ищут новых коллег. Поэтому оставляйте заявку до 25 июня, чтобы попасть в команду за выходные!
Подробности — на сайте.
🧠 JPA Batch Insert: ускоряем и защищаем от OOM
📌 Настройка Hibernate
Добавьте в application.yml или properties:
spring:
jpa:
properties:
hibernate.jdbc.batch_size: 50 # размер пакета
hibernate.order_inserts: true # группировка INSERT’ов
hibernate.order_updates: true # группировка UPDATE’ов
@Service
@RequiredArgsConstructor
public class OrderService {
private final EntityManager em;
private static final int BATCH_SIZE = 50;
@Transactional
public void saveAll(List<Order> orders) {
for (int i = 0; i < orders.size(); i++) {
em.persist(orders.get(i));
if (i > 0 && i % BATCH_SIZE == 0) {
em.flush();
em.clear(); // освобождаем persistence-context
}
}
em.flush();
em.clear();
}
}
flush() выталкивает пакеты в БД,clear() освобождает ОЗУ от управляемых сущностей.@SequenceGenerator с allocationSize.-Dorg.hibernate.SQL=DEBUG и -Dhibernate.format_sql=true — вы увидите групповые INSERT вместо множества одиночных.
📌 CRaC (Coordinated Restore at Checkpoint) — горячая JVM-фишка для сверхбыстрого cold-start: сохраняем состояние приложения после инициализации и моментально «восстанавливаем» при рестарте.
🧠 Как это работает
1. JVM создаёт снимок (checkpoint) всего heap- и native-состояния сразу после bootstrap и bean-инициализации.
2. При рестарте JVM грузит этот снимок вместо полной загрузки классов и прогрева JIT.
💡 Подключение в Java 21+
1. Включите экспериментальный модуль:
--add-modules jdk.crac
--enable-preview
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());
# Сохраняем 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
📌 Stream.toList() vs Collectors.toList() — безопасная замена?
🧠 В Java 16+ появился метод Stream.toList(), который собирает элементы потока в список. Раньше мы писали:
List<String> list = stream.collect(Collectors.toList());
List<String> list = stream.toList();
toList() возвращает unmodifiable List — любые add()/remove() вылетят UnsupportedOperationException.collect(Collectors.toList()) или
stream.collect(Collectors.toCollection(ArrayList::new));
toList() не допускает null и бросит NPE при встрече null в потоке. Collectors.toList() сохранит null без ошибок.Stream.toList() гарантированно создаёт новый список с точным размером, а Collectors.toList() лишь «может» вернуть любой List (часто ArrayList, но без чётких гарантий).toList().null — смело переходите на toList() для более лаконичного и потенциально более эффективного кода.toList() везде, где нужен только чтение — получилось короче и понятнее.
Test Driven Development (TDD) in Java
Creating a Queue Abstract Data Type class
Introduction to Test Doubles Dummies and Stubs
Introduction to Test Doubles Spies
Introduction to Test Doubles Mocks
Introduction to Test Doubles - Fakes
источник
👉@BookJava
📚 Эффективное сжатие текста: код Хаффмана в действии
Приглашаем на открытый урок.
🗓 11 июня в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Алгоритмы и структуры данных».
На этом вебинаре мы продолжим разработку архиватора, реализовав код Хаффмана.
✔️ Рассмотрим, как построить дерево кодов, где частота появления символов определяет их битовое представление.
✔️ Интегрируем алгоритм в наш архиватор и проведем сравнительное тестирование с RLE.
✔️ Увидим, как эффективно работает код Хаффмана на текстовых файлах и других типах данных.
Отличная возможность изучить продвинутые древовидные структуры данных на практическом примере.
Развивайте алгоритмическое мышление, увеличивайте производительность программ.
🎁 Всем участникам вебинара дарим промокод, который дает скидку на обучение - Algo5
👉 Регистрация на вебинар: https://vk.cc/cMzyUv
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576