Библиотека Java разработчика
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP
Ko'proq ko'rsatish📈 Telegram kanali Библиотека Java разработчика analitikasi
Библиотека Java разработчика (@bookjava) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 10 123 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 11 760-o'rinni va Rossiya mintaqasida 63 248-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 10 123 obunachiga ega bo‘ldi.
25 Avgust, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -74 ga, so‘nggi 24 soatda esa -6 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 7.20% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 3.71% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 729 marta ko‘riladi; birinchi sutkada odatda 376 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 5 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent string, интерфейс, строка, boot, api kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.
По всем вопросам @evgenycarter
РКН clck.ru/3KoGeP”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 26 Avgust, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
Ma'lumot yuklanmoqda...
| Sana | Obunachilarni jalb qilish | Esdaliklar | Kanallar | |
| 26 Avgust | 0 | |||
| 25 Avgust | +1 | |||
| 24 Avgust | +3 | |||
| 23 Avgust | 0 | |||
| 22 Avgust | 0 | |||
| 21 Avgust | +1 | |||
| 20 Avgust | 0 | |||
| 19 Avgust | +2 | |||
| 18 Avgust | +1 | |||
| 17 Avgust | 0 | |||
| 16 Avgust | 0 | |||
| 15 Avgust | +1 | |||
| 14 Avgust | 0 | |||
| 13 Avgust | 0 | |||
| 12 Avgust | 0 | |||
| 11 Avgust | +4 | |||
| 10 Avgust | 0 | |||
| 09 Avgust | 0 | |||
| 08 Avgust | 0 | |||
| 07 Avgust | 0 | |||
| 06 Avgust | 0 | |||
| 05 Avgust | +1 | |||
| 04 Avgust | +1 | |||
| 03 Avgust | 0 | |||
| 02 Avgust | 0 | |||
| 01 Avgust | +1 |
@Scheduled и многопоточностью
Когда используете @Scheduled для периодических задач в Spring Boot, важно понимать: по умолчанию все задачи выполняются в одном потоке.
@Scheduled(fixedRate = 5000)
public void syncData() {
// долгая операция
}
📌 Если таких задач несколько или они работают долго — остальные ждут. Это создаёт бутылочное горлышко и приводит к неожиданным задержкам.
💡 Решение: настроить кастомный executor:
@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar registrar) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5); // количество параллельных задач
scheduler.setThreadNamePrefix("scheduled-task-");
scheduler.initialize();
registrar.setTaskScheduler(scheduler);
}
}
Теперь все @Scheduled - методы будут использовать пул потоков, а не один.
⚠️ Не забывайте: если задача критична к ресурсам или зависит от внешних сервисов — добавьте внутреннюю защиту от повторного выполнения, например, с помощью Redis lock или базы.
✅ Подключение пула — must-have для production-проектов, где @Scheduled выполняет реальные задачи, а не просто println.
📲 Мы в MAX
👉@BookJava| 2 | 🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин
https://max.ru/channel_win_sysadmin Системный Администратор Windows
https://max.ru/channel_linux_admin Linux: Системный администратор
https://max.ru/channel_linuxmod Linux
https://max.ru/channel_i_linux Системный администратор
https://max.ru/channel_devopslib DevOps, SRE, Sysadmin
https://max.ru/channel_devops_star DevOps Star (Звезда Девопса)
Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак
Английский с нуля 🇬🇧
https://max.ru/UchuEnglish
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://max.ru/channel_DevLab1C 1С:Предприятие 8
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
https://max.ru/channel_cpp_geek C++ geek
Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика
Программирование React📌
https://max.ru/react_lib React
Программирование Rust📌
https://max.ru/channel_rust_lib
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
https://max.ru/channel_java_geek Java Geek
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии в IT📌
https://max.ru/progjob
https://max.ru/channel_rabotait
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Городские📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
https://max.ru/channel_krasnodar_novosty Краснодар Новости
https://max.ru/channel_novosibirsk_novosti Новосибирск
https://max.ru/channel_samara_novosti Новости Самары
https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга
https://max.ru/channel_kazan_novosti Новости Казани
https://max.ru/channel_omsk_novosti Новости Омска
https://max.ru/channel_moskva_24 Москва 24 | 408 |
| 3 | 💡 Не делай этого в @PostConstruct — особенно в проде
Сейчас расскажу, почему инициализировать важную бизнес-логику в @PostConstruct — плохая идея.
Типичный пример:
@Component
public class CacheLoader {
private final SomeService service;
public CacheLoader(SomeService service) {
this.service = service;
}
@PostConstruct
public void init() {
service.loadDataIntoCache(); // ⚠️ обращение к БД
}
}
🧨 Проблема: @PostConstruct вызывается до того, как приложение полностью поднялось.
Если внутри будет ошибка (например, БД недоступна) — приложение может упасть, или что хуже — запуститься в полурабочем состоянии.
📌 Кроме того:
* ❌ Нет контроля над порядком выполнения таких методов;
* ❌ Нельзя легко переиспользовать эту логику (например, вручную перезагрузить кеш);
* ❌ В тестах или dev-среде — такие вызовы часто мешают.
✅ Современный подход — использовать ApplicationListener:
@Component
public class CacheLoader implements ApplicationListener<ApplicationReadyEvent> {
private final SomeService service;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
service.loadDataIntoCache(); // 👍 вызывается только после старта
}
}
📌 Альтернатива — аннотация @EventListener:
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
// безопасно загружаем данные
}
📦 В Spring Boot это нативный и рекомендованный способ выполнения кода после старта.
🧠 Резюме:
🔹 @PostConstruct — только для простой инициализации бинов.
🔹 Бизнес-логику и I/O — в @EventListener(ApplicationReadyEvent.class).
📲 Мы в MAX
👉@BookJava | 608 |
| 4 | 🧠 JVM-разработчики, стягиваемся в Москву 29 августа
В последнюю субботу лета бэкенд- и JVM-комьюнити соберется на JVM Day, который устраивает Т-Банк. Ждут всех разработчиков, архитекторов и тимлидов, которые работают с Java, Kotlin и Scala.
В программе:
– Андрей Кулешов расскажет о том, что изменилось в мире JVM за год.
– Сергей Петрелевич разберет Mechanical Sympathy.
– Александр Ланцов покажет, какие модели конкурентности актуальны после появления Loom.
– Антон Курако объяснит, почему красивые показатели бенчмарков могут вводить в заблуждение.
А после докладов во дворе штаб-квартиры Т-Банка пройдут:
– Игры на Sega и ИТ-Квиз.
– PowerPoint Party и открытый микрофон с историями ошибок.
– Диджей-сет на виниле под открытым небом.
Места ограничены, регистрироваться тут. Пишите в комментариях, если идете на конфу.
📲 Мы в MAX
👉@BookJava | 749 |
| 5 | 🧠 @Value в Spring — это ловушка, если вы используете списки или map'ы
Многие знают, что можно заинжектить список строк из application.yml вот так:
app:
langs:
- en
- fr
- de
@Value("${app.langs}")
private List<String> langs;
Но знаете, что вы получите?
⚠️ ОШИБКУ. @Value не умеет парсить YAML-массивы. Он ожидает строку, и даже с CSV-строкой (en,fr,de) — всё не так очевидно: Spring не применяет ConversionService для списков.
📌 Решение — использовать @ConfigurationProperties:
app:
langs:
- en
- fr
- de
@ConfigurationProperties(prefix = "app")
@Component
public class AppProps {
private List<String> langs;
// геттеры/сеттеры
}
💡 Профит:
- работает с List, Map, вложенными объектами;
- валидация через @Validated и @NotEmpty;
- легко покрыть тестами;
- меньше магии.
⚠️ @Value хорош для простых скаляров. Всё остальное — через @ConfigurationProperties.
📲 Мы в MAX
👉@BookJava | 659 |
| 6 | 👩💻 Работа с Kafka через библиотеку Kafka Clients
Приглашаем на открытый урок.
🗓 26 августа в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java разработчик. Продвинутый уровень».
Kafka Clients это нижний уровень для работы с Kafka из Java. Все более высокоуровневые библиотеки основаны на нем.
Данный открытый урок проходит в рамках курса Java разработчик. Продвинутый уровень.
О чем поговорим:
✔️ Чтение и отправка сообщений в Kafka
✔️ Управление топиками
✔️ Разные форматы: текст, JSON, Avro
✔️ Использование транзакций
🔗 Ссылка на регистрацию: https://vk.cc/d0zMZ5
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576 | 646 |
| 7 | 🧠 Нюанс с Optional.map() и методами, возвращающими Optional
Многие Java-разработчики на автомате пишут что-то вроде:
Optional<User> user = findUserById(id); // возвращает Optional<User>
Optional<String> email = user.map(User::getEmail); // getEmail тоже возвращает Optional<String>
⚠️ Проблема: map() в Optional не "разворачивает" вложенные Optional. В этом примере email будет типа Optional<Optional<String>>, что почти всегда нежелательно.
📌 Правильный способ — использовать flatMap():
Optional<String> email = user.flatMap(User::getEmail);
💡 flatMap() позволяет избежать "двойной обёртки", если метод внутри map() уже возвращает Optional.
🔁 Аналогичная ситуация с Stream.map() — если внутри map() вызывается метод, возвращающий Stream, то получится Stream<Stream<T>>, и опять же нужно использовать flatMap().
🧪 Мини-памятка:
* map() — когда метод возвращает обычный тип (T → R);
* flatMap() — когда метод возвращает Optional или Stream (T → Optional<R> или T → Stream<R>).
📲 Мы в MAX
👉@BookJava | 618 |
| 8 | Почему ты получаешь отказ после "норм собеса"?
Дело не в знаниях - ты просто не знаешь, что реально проверяют на собеседованиях
Отсюда:
— непонимание, какие навыки надо качать, чтобы выйти на следующий грейд
— ощущение стагнации и отсутствие роста в скиллах
— долгое время на одной и той же зп
Решение — знать, что от тебя ждёт интервьюер, и умение правильно донести свою мысль
Для этого ребята из ШОРТКАТ (менторской программы для разработчиков) собрали в один файл ОТВЕТЫ НА 50 СЛОЖНЫХ ВОПРОСОВ с Java-собеседований 🔥
Они проанализировали более 100 мок-интервью и собрали внутри реальные вопросы + ответы сильного кандидата
Забрать можно бесплатно (!) в боте — @shortcut_sh_bot
Переходите по ссылке выше и забирайте файл, чтобы быстрее выйти на новый уровень ☝️
Реклама.
О рекламодателе. | 607 |
| 9 | Java. Сортировки
Java. Сортировка пузырьком.
Java. О сортировке выбором.
Java. Быстрая сортировка. Объяснение на пальцах)
Java. Оценка сложности алгоритмов сортировки.
Java. Сортировка слиянием.
Java. Сортировка подсчетом.
Java. Сортировка вставками.
Java. Сортировка расческой. От пузырька до расчески.
📲 Мы в MAX
👉@BookJava | 774 |
| 10 | 🧠 Как в Java сломать equals() и потерять данные в HashMap
Сегодня покажу, как неочевидный баг в equals()/hashCode() может привести к потере данных при работе с HashMap.
Допустим, у вас есть Entity:
public class User {
private String id;
private String name;
// equals/hashCode только по id
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
Вроде норм. Но теперь добавим такого юзера в HashMap, а потом... изменим его id:
User user = new User();
user.setId("1");
user.setName("Alice");
Map<User, String> map = new HashMap<>();
map.put(user, "value");
user.setId("2"); // ⚠️ ключ стал "невидимым"
System.out.println(map.get(user)); // null 😱
📌 Почему так происходит?
HashMap ищет ключ по hashCode() → ищет бакет → сравнивает через equals(). А hashCode() уже другой, и объект "теряется".
💡 Совет: если вы используете объект как ключ в мапе или добавляете его в Set, не изменяйте его поля, участвующие в equals()/hashCode()!
📌 А как правильно?
- Делайте такие поля final;
- Или используйте неизменяемые типы (record);
- Или не используйте такие объекты как ключи вовсе.
Вот безопасный вариант с record:
public record User(String id, String name) {}
📲 Мы в MAX
👉@BookJava | 762 |
| 11 | 💡Сегодня покажу крутую фишку для оптимизации чтения больших коллекций из базы через JPA.
📌 Проблема:
Когда загружаем большую коллекцию через @OneToMany, Hibernate часто делает это лениво (LAZY), но при первом доступе — забирает всю коллекцию целиком.
Это может привести к OutOfMemoryError или резкому проседанию производительности.
📌 Решение: использовать пагинацию (batch-size) или запрос коллекции порциями.
Как настроить batch-size на уровне сущности:
@Entity
public class User {
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
@BatchSize(size = 50)
private List<Order> orders;
}
🧠 Теперь Hibernate будет загружать за раз по 50 элементов, а не всю коллекцию сразу!
📌 Или можно настроить глобально через application.properties:
spring.jpa.properties.hibernate.default_batch_fetch_size=50
⚠️ Важно:
- @BatchSize работает только для LAZY-связей.
- Это не пагинация в SQL, а оптимизация внутренних запросов Hibernate.
- Если коллекция огромная (100k+ записей) — лучше делать явные paged запросы в репозитории.
💡Помните: без настройки batch-size Hibernate может сломать приложение под нагрузкой. Оптимизируйте загрузку коллекций заранее!
📲 Мы в MAX
👉@BookJava | 707 |
| 12 | Как работают instance initializer blocks.
Пример с родительским и дочерним классами:
class Parent {
int a = 5;
{
System.out.println("Parent instance initializer");
a = 10;
}
Parent() {
System.out.println("Parent constructor, a = " + a);
}
}
class Child extends Parent {
int b = 15;
{
System.out.println("Child instance initializer");
b = 25;
}
Child() {
System.out.println("Child constructor, b = " + b);
}
}
public class Test {
public static void main(String[] args) {
Child child = new Child();
}
}
Вывод программы:
Parent instance initializer
Parent constructor, a = 10
Child instance initializer
Child constructor, b = 25
Пошаговое выполнение:
1. Сначала загружается родительский класс Parent.
2. Выполняется:
- Инициализация полей родителя (a = 5),
- Потом instance initializer блока родителя (a = 10),
- Потом конструктор родителя (Parent()).
3. Далее переходим к дочернему классу Child:
- Инициализация полей дочернего класса (b = 15),
- Потом instance initializer блока дочернего класса (b = 25),
- Потом конструктор дочернего класса (Child()).
Важный порядок действий:
1. Инициализация родителя → 2. Конструктор родителя → 3. Инициализация потомка → 4. Конструктор потомка.
Блоки инициализации всегда выполняются до тела конструктора, но после вызова super().
📲 Мы в MAX
👉@BookJava | 822 |
| 13 | 🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
https://max.ru/tipsysdmin Типичный Сисадмин
https://max.ru/channel_win_sysadmin Системный Администратор Windows
https://max.ru/channel_linux_admin Linux: Системный администратор
https://max.ru/channel_linuxmod Linux
https://max.ru/channel_i_linux Системный администратор
https://max.ru/channel_devopslib DevOps, SRE, Sysadmin
https://max.ru/channel_devops_star DevOps Star (Звезда Девопса)
Excel лайфхак 📌
https://t.me/Excel_lifehack Excel лайфхак
Английский с нуля 🇬🇧
https://max.ru/UchuEnglish
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://max.ru/channel_DevLab1C 1С:Предприятие 8
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
https://max.ru/channel_cpp_geek C++ geek
Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика
Программирование React📌
https://max.ru/react_lib React
Программирование Rust📌
https://max.ru/channel_rust_lib
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
https://max.ru/channel_java_geek Java Geek
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии в IT📌
https://max.ru/progjob
https://max.ru/channel_rabotait
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Городские📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
https://max.ru/channel_krasnodar_novosty Краснодар Новости
https://max.ru/channel_novosibirsk_novosti Новосибирск
https://max.ru/channel_samara_novosti Новости Самары
https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга
https://max.ru/channel_kazan_novosti Новости Казани
https://max.ru/channel_omsk_novosti Новости Омска
https://max.ru/channel_moskva_24 Москва 24 | 745 |
| 14 | В Java instance initializer blocks (блоки инициализации экземпляра) выполняются в следующем порядке:
- Они выполняются каждый раз, когда создается новый объект класса.
- Выполнение происходит после вызова конструктора родительского класса (super()), но до тела конструктора текущего класса.
Порядок инициализации:
1. Сначала инициализируются поля в порядке их объявления.
2. Затем выполняются instance initializer blocks, в том порядке, в котором они написаны в коде.
3. После этого выполняется тело конструктора.
Пример:
class Example {
int x = 10;
{
System.out.println("Instance initializer block");
x = 20;
}
Example() {
System.out.println("Constructor");
System.out.println("x = " + x);
}
public static void main(String[] args) {
Example ex = new Example();
}
}
Вывод:
Instance initializer block
Constructor
x = 20
Ключевые моменты:
- Статические блоки (static {}) — другое дело: они выполняются один раз при загрузке класса.
- Instance initializer blocks полезны для общей инициализации, которую нужно выполнять вне зависимости от того, какой конструктор вызывается.
📲 Мы в MAX
👉@BookJava | 835 |
| 15 | 🔴 Завтра тестовое собеседование с Java-разработчиком
5 августа(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе. | 869 |
| 16 | 🧠 Сегодня покажу вам полезный трюк для Spring Boot: как элегантно валидировать параметры контроллера без лишнего кода.
Часто вижу, как в контроллерах вручную проверяют @RequestParam на пустоту или формат. Это шумит код и приводит к ошибкам.
Вместо этого используйте аннотации валидации прямо на параметрах:
@RestController
@RequestMapping("/api")
@Validated // Обязательно!
public class UserController {
@GetMapping("/users")
public List<User> getUsers(
@RequestParam @NotBlank String name,
@RequestParam @Min(18) int age
) {
// Если валидация не пройдена — автоматически вернётся 400 Bad Request
return userService.findUsers(name, age);
}
}
📌 Ключевые моменты:
- Обязательно ставим @Validated над классом контроллера.
- На параметры добавляем любые стандартные аннотации из jakarta.validation.constraints.
- Ошибки валидации Spring обработает автоматически через MethodArgumentNotValidException.
💡 Можно кастомизировать ответ на ошибку, добавив глобальный @ExceptionHandler.
⚠️ Без @Validated аннотации на контроллере валидация параметров работать не будет!
📲 Мы в MAX
👉@BookJava | 760 |
| 17 | 🧠 JPA: подводный камень с @ElementCollection и fetch = FetchType.EAGER
Сегодня покажу, почему @ElementCollection(fetch = FetchType.EAGER) — скрытая угроза производительности и неожиданного поведения.
📌 Суть проблемы
При использовании @ElementCollection с EAGER Hibernate делает отдельный SELECT на каждую коллекцию, даже при JOIN FETCH на родительскую сущность.
@Entity
class User {
@Id Long id;
@ElementCollection(fetch = FetchType.EAGER)
List<String> tags;
}
Запрос findAll() приведёт к N+1 проблеме:
1 запрос на User, потом по одному на каждый tags.
💡 Почему это больно
Даже если вы используете JOIN FETCH на User, Hibernate не может сделать JOIN на @ElementCollection. Это ограничение — Hibernate всегда грузит коллекцию отдельным запросом.
⚠️ Особенно опасно при pagination
Если вы делаете Page<User> — Hibernate сначала грузит User'ов, а затем делает N запросов на коллекции. В проде это быстро становится проблемой.
✅ Что делать
1. Делайте fetch = FetchType.LAZY (по умолчанию так и есть).
2. Если нужно подгрузить коллекцию — используйте @BatchSize:
@ElementCollection
@BatchSize(size = 20)
List<String> tags;
Или вручную:
SELECT u FROM User u LEFT JOIN FETCH u.tags WHERE u.id IN :ids
👉 Следи за @ElementCollection — он не так прост, как кажется.
📲 Мы в MAX
👉@BookJava | 925 |
| 18 | 🧠 Как избежать N+1 при использовании @OneToMany в JPA
Одна из самых коварных ловушек JPA - это N+1 проблема. Особенно часто она проявляется при @OneToMany, например:
@Entity
class Author {
@OneToMany(mappedBy = "author", fetch = FetchType.LAZY)
private List<Book> books;
}
Вы загружаете список авторов, а потом проходите по каждому и вызываете getBooks() — и BAM 💥: 1 запрос на авторов и N запросов на книги.
📌 Решение - @EntityGraph или JOIN FETCH
Оба варианта решают проблему, но @EntityGraph — декларативный и более гибкий способ:
@EntityGraph(attributePaths = "books")
List<Author> findAll(); // Spring Data JPA
⚡️ Или через JPQL:
@Query("SELECT a FROM Author a JOIN FETCH a.books")
List<Author> findAllWithBooks();
💡 Совет: всегда думайте о графе объектов. Если вам нужно сразу подтянуть связанные сущности — делайте это явно. Не надейтесь на LAZY по умолчанию.
⚠️ Осторожно с пагинацией и JOIN FETCH — могут появиться дубликаты или проблемы с LIMIT. В таких случаях лучше использовать @BatchSize или подзапросы.
📲 Мы в MAX
👉@BookJava | 963 |
| 19 | Чем отличаются checked и unchecked исключения в java?
В Java исключения делятся на два основных типа: checked и unchecked. Разница между ними ключевая и касается как обработки, так и структуры кода.
✅ Checked Exceptions (Проверяемые исключения)
Примеры: IOException, SQLException, FileNotFoundException
Отличия:
1. Проверяются компилятором — вы обязаны либо обработать их с помощью try-catch, либо явно пробросить (throws) в сигнатуре метода.
2. Производные от Exception, но не от RuntimeException.
3. Используются для ситуаций, которые можно разумно ожидать и обработать (например, отсутствие файла, проблемы с сетью).
Пример:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // может выбросить IOException
}
❌ Unchecked Exceptions (Непроверяемые исключения)
Примеры: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException
Отличия:
1. Не проверяются компилятором — вы не обязаны их обрабатывать или декларировать.
2. Производные от RuntimeException.
3. Возникают в результате ошибок в логике программы или непредвиденных ситуаций.
Пример:
public void printLength(String str) {
System.out.println(str.length()); // может выбросить NullPointerException
}
Если кратко:
Checked — ошибки среды, требующие явной обработки.
Unchecked — ошибки в логике, ответственность программиста.
📲 Мы в MAX
👉@BookJava | 883 |
| 20 | 🧠 JPA: не забывай про flush() перед clear() — иначе словишь баг
Если ты используешь EntityManager вручную, например, при батчевой вставке или обновлении, то, скорее всего, пишешь что-то вроде:
for (int i = 0; i < entities.size(); i++) {
em.persist(entities.get(i));
if (i % 50 == 0) {
em.clear(); // чтобы не росла память
}
}
⚠️ Но тут баг: без flush() перед clear() ты теряешь все неперсистенные изменения! Hibernate просто забудет про них.
✅ Правильно так:
for (int i = 0; i < entities.size(); i++) {
em.persist(entities.get(i));
if (i % 50 == 0) {
em.flush();
em.clear();
}
}
📌 flush() гарантирует, что все накопленные изменения пойдут в базу, а clear() уже безопасно очищает контекст.
💡 Эта ошибка особенно коварна, потому что не всегда проявляется — зависит от настроек, триггеров в БД, кэша и т.д.
📲 Мы в MAX
👉@BookJava | 933 |
