uz
Feedback
Библиотека Java разработчика

Библиотека Java разработчика

Kanalga Telegram’da o‘tish

📚 Лайфхаки, приёмы и лучшие практики для 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 042 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 11 640-o'rinni va Rossiya mintaqasida 62 744-o'rinni egallagan.

📊 Auditoriya ko‘rsatkichlari va dinamika

невідомо sanasidan buyon loyiha tez o‘sib, 10 042 obunachiga ega bo‘ldi.

05 Oktabr, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -48 ga, so‘nggi 24 soatda esa -2 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.

  • Tasdiqlash holati: Tasdiqlanmagan
  • Jalb etish (ER): Auditoriya o‘rtacha 8.21% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 3.65% ini tashkil etuvchi reaksiyalarni to‘playdi.
  • Post qamrovi: Har bir post o‘rtacha 825 marta ko‘riladi; birinchi sutkada odatda 367 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 06 Oktabr, 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.

10 042
Obunachilar
-224 soatlar
-177 kun
-4830 kun
Obunachilarni jalb qilish
Okt '26
Oktabr '26
+1
0 kanalda
Sentabr '26
+27
0 kanalda
Get PRO
Avgust '26
+17
0 kanalda
Get PRO
Iyul '26
+20
0 kanalda
Get PRO
Iyun '26
+46
0 kanalda
Get PRO
May '26
+64
0 kanalda
Get PRO
Aprel '26
+27
0 kanalda
Get PRO
Mart '26
+28
0 kanalda
Get PRO
Fevral '26
+39
0 kanalda
Get PRO
Yanvar '26
+43
1 kanalda
Get PRO
Dekabr '25
+16
0 kanalda
Get PRO
Noyabr '25
+72
31 kanalda
Get PRO
Oktabr '25
+47
1 kanalda
Get PRO
Sentabr '25
+61
36 kanalda
Get PRO
Avgust '25
+55
0 kanalda
Get PRO
Iyul '25
+63
27 kanalda
Get PRO
Iyun '25
+44
19 kanalda
Get PRO
May '25
+65
44 kanalda
Get PRO
Aprel '25
+90
38 kanalda
Get PRO
Mart '25
+78
38 kanalda
Get PRO
Fevral '25
+100
31 kanalda
Get PRO
Yanvar '25
+83
33 kanalda
Get PRO
Dekabr '24
+116
34 kanalda
Get PRO
Noyabr '24
+67
32 kanalda
Get PRO
Oktabr '24
+99
29 kanalda
Get PRO
Sentabr '24
+131
28 kanalda
Get PRO
Avgust '24
+97
18 kanalda
Get PRO
Iyul '24
+45
0 kanalda
Get PRO
Iyun '24
+99
23 kanalda
Get PRO
May '24
+234
18 kanalda
Get PRO
Aprel '24
+210
0 kanalda
Get PRO
Mart '24
+282
21 kanalda
Get PRO
Fevral '24
+274
17 kanalda
Get PRO
Yanvar '24
+329
23 kanalda
Get PRO
Dekabr '23
+222
23 kanalda
Get PRO
Noyabr '23
+117
16 kanalda
Get PRO
Oktabr '23
+136
18 kanalda
Get PRO
Sentabr '23
+243
0 kanalda
Get PRO
Avgust '23
+325
0 kanalda
Get PRO
Iyul '23
+322
0 kanalda
Get PRO
Iyun '23
+306
0 kanalda
Get PRO
May '23
+287
0 kanalda
Get PRO
Aprel '23
+271
0 kanalda
Get PRO
Mart '23
+603
0 kanalda
Get PRO
Fevral '23
+153
0 kanalda
Get PRO
Yanvar '23
+214
0 kanalda
Get PRO
Dekabr '22
+206
0 kanalda
Get PRO
Noyabr '22
+140
0 kanalda
Get PRO
Oktabr '22
+207
0 kanalda
Get PRO
Sentabr '22
+226
0 kanalda
Get PRO
Avgust '22
+288
0 kanalda
Get PRO
Iyul '22
+299
0 kanalda
Get PRO
Iyun '22
+278
0 kanalda
Get PRO
May '22
+315
0 kanalda
Get PRO
Aprel '22
+318
0 kanalda
Get PRO
Mart '22
+417
0 kanalda
Get PRO
Fevral '22
+328
0 kanalda
Get PRO
Yanvar '22
+245
0 kanalda
Get PRO
Dekabr '21
+222
0 kanalda
Get PRO
Noyabr '21
+172
0 kanalda
Get PRO
Oktabr '21
+323
0 kanalda
Get PRO
Sentabr '21
+207
0 kanalda
Get PRO
Avgust '21
+331
0 kanalda
Get PRO
Iyul '21
+310
0 kanalda
Get PRO
Iyun '21
+271
0 kanalda
Get PRO
May '21
+297
0 kanalda
Get PRO
Aprel '21
+328
0 kanalda
Get PRO
Mart '21
+419
0 kanalda
Get PRO
Fevral '21
+436
0 kanalda
Get PRO
Yanvar '21
+452
0 kanalda
Get PRO
Dekabr '20
+7 112
0 kanalda
Sana
Obunachilarni jalb qilish
Esdaliklar
Kanallar
06 Oktabr0
05 Oktabr0
04 Oktabr+1
03 Oktabr0
02 Oktabr0
01 Oktabr0
Kanal postlari
🧠 Dependency Inversion Principle (D в SOLID) Зависимости должны идти от высокоуровневой политики к низкоуровневым деталям, а не наоборот. Абстракции — хозяева, реализации — обслуживающий персонал. 📌 Коротко о сути * Модули верхнего уровня (бизнес-логика) зависят только от интерфейсов/абстракций. * Модули нижнего уровня (база, сеть, файлы) также зависят от тех же абстракций. * Сами абстракции не знают ничего о деталях, тем самым разрывая «бетонную» сцепку между слоями. 💡 Мини-пример (Java 17+, Spring Boot 3+)

// 1️⃣ Абстракция — контракт
public interface NotificationSender {
    void send(Message msg);
}

// 2️⃣ Верхний уровень — бизнес-служба
@Service
public class BillingService {
    private final NotificationSender sender;

    public BillingService(NotificationSender sender) {
        this.sender = sender;                 // зависим от контракта
    }

    public void bill(Client c) {
        // ...
        sender.send(new Message("Invoice #42"));
    }
}

// 3️⃣ Низкий уровень — деталь
@Component
public class EmailSender implements NotificationSender {
    public void send(Message msg) {
        // SMTP-магия
    }
}
BillingService может жить в модульном jar без spring-email-starter и SMTP-кода — протестировать его теперь элементарно. ⚠️ Где рождаются проблемы 1. Путаница DI container ≠ DIP IoC/DI-фреймворк (Spring, CDI) — лишь удобный способ «сращивать» зависимости, но принцип работает и без контейнера (чистый constructor injection). 2. Абстракции ради галочки Интерфейс OneImplService с единственной реализацией ломает читаемость, тесты и автоконфиг 📉. ➜ Создавай абстракцию, когда реально нужны сменяемость, тестируемость или расширяемость. 3. Утечки деталей Если интерфейс таскает DTO из слоя хранения, ты всё ещё «протёк» к базе. Держи контракты чистыми. 4. Слепая вера в фреймворк Жизненный цикл бинов, прокси, lazy-init — магия мешает понимать, кто кем владеет. ➜ Всегда можешь собрать объект вручную в юнит-тесте. Если сложно — запах нарушения DIP. 5. Слишком много уровней абстракций «Контроллер → сервис → менеджер → порт → адаптер → репозиторий» превращает код в матрёшку. Дизайн важнее количества слоёв. 📝 Практические советы * Используй constructor injection по умолчанию. Поле final = явная зависимость. * Группируй интерфейсы по use-case, а не по технологии (например, TransferPort, а не JdbcTransferRepository). * В тестах не мокай фреймворк — мокай контракт. * Для одноразовых реализаций начни с class. Если появится второй вариант — быстро вынесешь интерфейс (IDE поможет). * Проверка себя: можно ли запустить модуль верхнего уровня без нижнего? Если да — DIP соблюдён. 💬 Итог DIP — это не про «везде интерфейсы» и не про «подключи Spring». Это про правильное направление зависимостей, которое делает код гибким, тестируемым и не заложником технологий. А проблемы возникают, когда путают инструмент с принципом и забывают, что абстракция должна прятать детали, а не выпячивать их. 📲 Мы в MAX 👉@BookJava

2
Три похожих слова в Java — final, finally, finalize — но смысл у них совершенно разный. Разберёмся 🧠 🔒 final Ключевое слово
Три похожих слова в Java — final, finally, finalize — но смысл у них совершенно разный. Разберёмся 🧠 🔒 final Ключевое слово. Используется для ограничений: * final class — нельзя наследовать. * final method — нельзя переопределить. * final variable — нельзя изменить значение (один раз присвоил — всё). 📌 Особенно важно для immutability и thread-safety. final int x = 10; x = 20; // ошибка компиляции 🧯 finally Блок в конструкции try-catch-finally. Выполняется всегда, даже если был return или exception. 💡 Используется для освобождения ресурсов: закрытия потоков, соединений и т.д. try { // что-то может выбросить исключение } catch (Exception e) { // обработка ошибки } finally { // всегда выполнится } ⚰️ finalize() Метод из Object, вызывался перед удалением объекта сборщиком мусора. ⚠️ УСТАРЕЛ с Java 9, удалён в Java 18. Не используй. 🔪 Непредсказуем, плохо работает, тормозит GC. Вместо него — AutoCloseable и try-with-resources. @Override protected void finalize() throws Throwable { System.out.println("До свидания..."); } 🧠 Важно не путать: * final — про нельзя менять * finally — про всегда выполнится * finalize — про устаревший и бесполезный метод 📲 Мы в MAX 👉@BookJava
636
3
🧠 Ленивая инициализация через Supplier — элегантная альтернатива double-checked locking Когда нужно отложить создание тяжёло
🧠 Ленивая инициализация через Supplier — элегантная альтернатива double-checked locking Когда нужно отложить создание тяжёлого объекта до первого обращения, многие вспоминают double-checked locking: private volatile SomeHeavyObject obj; public SomeHeavyObject getObj() { if (obj == null) { synchronized (this) { if (obj == null) { obj = new SomeHeavyObject(); } } } return obj; } ⚠️ Многословно, хрупко, легко ошибиться. Есть лучше. 📌 Современный подход — использовать Supplier с ленивой инициализацией: private final Supplier<SomeHeavyObject> lazyObj = Suppliers.memoize(SomeHeavyObject::new); public SomeHeavyObject getObj() { return lazyObj.get(); } 💡 Suppliers.memoize — из Guava. Он гарантирует потокобезопасную инициализацию один раз при первом вызове get(). Плюсы: — Читается за секунду — Потокобезопасно — Нет дублирования кода — Легко тестировать и заменять 🔁 Альтернатива в чистой Java: использовать AtomicReference и updateAndGet, но это уже длиннее и менее выразительно. Если используешь Spring — можно просто обернуть бин в @Lazy. Но вне Spring, в обычных Java-приложениях или утилитах — Supplier с memoize() идеален. 📲 Мы в MAX 👉@BookJava
725
4
Что такое механизм try-with-resources? Механизм try-with-resources в Java — это конструкция, которая упрощает работу с ресурс
Что такое механизм try-with-resources? Механизм try-with-resources в Java — это конструкция, которая упрощает работу с ресурсами, требующими закрытия (например, файлы, сокеты, соединения с БД и т.д.). Он автоматически закрывает ресурсы после завершения блока try, избавляя от необходимости писать finally вручную. 📌 Поддерживается с Java 7 📌 Ресурсы должны реализовывать интерфейс AutoCloseable 💡 Пример: try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) { String line = reader.readLine(); System.out.println(line); } catch (IOException e) { e.printStackTrace(); } // reader будет закрыт автоматически, даже если произойдёт исключение 🧠 Почему это важно: * Уменьшает boilerplate-код * Исключает утечки ресурсов * Упрощает обработку исключений ⚠️ Совет: С Java 9 можно использовать уже объявленные переменные, если они final или effectively final: BufferedReader reader = new BufferedReader(new FileReader("file.txt")); try (reader) { System.out.println(reader.readLine()); } 📲 Мы в MAX 👉@BookJava
890
5
📌 picocli — это современная библиотека для создания CLI-приложений на Java. Она упрощает разработку командных интерфейсов, о
📌 picocli — это современная библиотека для создания CLI-приложений на Java. Она упрощает разработку командных интерфейсов, обеспечивая: * Автоматическую генерацию --help и --version * Поддержку подкоманд (как в git commit, git push) * Аргументы, параметры, опции с короткими и длинными флагами (-v, --verbose) * Интеграцию с GraalVM (подходит для нативной компиляции) * Поддержку аннотаций (аннотируй POJO — и готово!) * Автоматическую валидацию аргументов * Цветной вывод и гибкое форматирование * Интерактивный режим и автодополнение Проект активно развивается, полностью документирован и используется в сотнях продакшн-проектов. Если ты ищешь мощную и простую в использовании CLI-библиотеку на Java — picocli отличный выбор. https://github.com/remkop/picocli 📲 Мы в MAX 👉@BookJava
898
6
Double-brace инициализация в Java — это идиома, которая используется для инициализации коллекций (и иногда других объектов) в
Double-brace инициализация в Java — это идиома, которая используется для инициализации коллекций (и иногда других объектов) в краткой форме. Она выглядит как две открывающие фигурные скобки подряд {{ и имеет специфическое поведение. Пример: import java.util.*; List<String> list = new ArrayList<String>() {{ add("one"); add("two"); add("three"); }}; Как это работает: Double-brace инициализация — это комбинация двух конструкций: 1. Анонимный внутренний класс: new ArrayList<String>() { ... } Создаётся новый безымянный подкласс ArrayList. 2. Инициализатор экземпляра: {{ ... }} Это блок, который выполняется при создании объекта. В него можно вставлять вызовы методов (например, add()). Преимущества: * Компактный и удобочитаемый синтаксис для заполнения коллекций. * Можно использовать в полях final, например: private static final Set<String> set = new HashSet<>() {{ add("A"); add("B"); }}; Недостатки: 1. Создаётся лишний анонимный класс — это увеличивает количество байткода и может мешать сериализации. 2. Утечки памяти — если такой класс находится внутри внешнего класса, он может неявно хранить ссылку на него. 3. Читаемость — не все разработчики знают, как это работает, и это может сбивать с толку. 4. Нарушение принципов OOP — логика инициализации размещается в конструкторе, который не явно виден. Альтернативы: Java 8+ (через Stream и Collectors): List<String> list = Stream.of("one", "two", "three") .collect(Collectors.toList()); Статический метод инициализации: public static List<String> createList() { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); return list; } Java 9+ (immutable): List<String> list = List.of("one", "two", "three"); Set<String> set = Set.of("A", "B"); Вывод: Double-brace инициализация — это удобный, но потенциально опасный трюк, который не рекомендуется использовать в продакшене. Лучше предпочесть более читаемые и безопасные альтернативы, особенно с учётом новых возможностей Java 8+. 📲 Мы в MAX 👉@BookJava
911
7
🧠@Value vs @ConfigurationProperties — не выбирай наобум Оба способа хороши для конфигурации, но используют их по-разному. И
🧠@Value vs @ConfigurationProperties — не выбирай наобум Оба способа хороши для конфигурации, но используют их по-разному. И если ты всё ещё везде пихаешь @Value, держи краткий гайд, когда лучше что: 📌 @Value — просто, но не гибко: @Value("${my.prop}") private String value; ✅ Хорошо для единичных значений ❌ Плохо для сложных структур, списков, валидации ❌ Трудно покрыть тестами (без TestPropertySource) ❌ Нет биндинга по префиксу → нет группировки 📌 @ConfigurationProperties — сила и масштаб: @ConfigurationProperties(prefix = "app.feature") public class FeatureProperties { private boolean enabled; private List<String> items; } 💡 Используй с @EnableConfigurationProperties или аннотируй как @Component ✅ Удобно группировать и документировать ✅ Работает с вложенными структурами, коллекциями ✅ Поддерживает JSR-303 валидацию (@Validated) ✅ Легче мокать в тестах ✅ Интеграция с Spring Boot Actuator (/actuator/configprops) ⚠️ Не смешивай: не нужно тянуть @Value внутрь @ConfigurationProperties — это антипаттерн. Если конфигурация простая — @Value норм. Но как только появляется структура, коллекции, логика — всегда используй @ConfigurationProperties. 📲 Мы в MAX 👉@BookJava
822
8
🧠 Трюк с @EventListener в Spring — убираем лишний @TransactionalEventListener Когда тебе нужно обрабатывать события в рамках
🧠 Трюк с @EventListener в Spring — убираем лишний @TransactionalEventListener Когда тебе нужно обрабатывать события в рамках транзакции, мы часто пишем: @TransactionalEventListener public void handleEvent(MyEvent event) { // ... } ⚠️ Но есть нюанс: @TransactionalEventListener по умолчанию срабатывает после коммита. Иногда это не очевидно и вызывает баги, особенно если ожидаешь, что событие обработается внутри транзакции. 📌 Альтернатива: обычный @EventListener, но вместе с TransactionSynchronizationManager. 💡 Сниппет: @Component public class MyEventHandler { @EventListener public void handle(MyEvent event) { if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization( new TransactionSynchronizationAdapter() { @Override public void afterCommit() { // обработка события после коммита } } ); } else { // fallback: нет активной транзакции — выполняем сразу } } } 📎 Плюсы: — Лучше контроль: ты сам решаешь, когда обрабатывать (до/после/вне транзакции) — Можно централизовать поведение через utility-метод — Гибкость: логика обработки не зависит от аннотаций Spring'а ⚠️ Минус: чуть больше кода, но понятнее поведение. 📲 Мы в MAX 👉@BookJava
845
9
👩‍💻 HTTP-сервер на чистой Java за 30 минут Приглашаем на открытый урок. 🗓 21 сентября в 20:00 МСК 🆓 Бесплатно. Урок в рам
👩‍💻 HTTP-сервер на чистой Java за 30 минут Приглашаем на открытый урок. 🗓 21 сентября в 20:00 МСК 🆓 Бесплатно. Урок в рамках старта курса «Java разработчик. Продвинутый уровень». Разберем, как браузер общается с сервером, и создадим работающий HTTP-сервис без Spring и сторонних библиотек. О чем поговорим: ✔️ Как устроен HTTP-запрос ✔️ Создадим сервер на Java ✔️ Добавим несколько адресов ✔️ Откроем результат в браузере ✔️ Разберём, что скрывает Spring 🔗 Ссылка на регистрацию: https://vk.cc/d1sLwn Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
1 084
10
🧠 Как не словить LazyInitializationException в Spring Boot + Hibernate Одна из самых частых ошибок при работе с JPA: org.hib
🧠 Как не словить LazyInitializationException в Spring Boot + Hibernate Одна из самых частых ошибок при работе с JPA: org.hibernate.LazyInitializationException: failed to lazily initialize a collection 📌 Причина: лениво загружаемая коллекция (LAZY) обращается к БД вне транзакции — например, в слое контроллера или после закрытия Session. 💡 Как избежать? ✅ Решение 1: @Transactional в сервисе Убедитесь, что вы обращаетесь к ленивым коллекциям внутри метода с @Transactional: @Transactional public UserDto getUser(Long id) { User user = userRepository.findById(id) .orElseThrow(); // OK: коллекция friends будет инициализирована в транзакции return new UserDto(user.getName(), user.getFriends()); } ⚠️ Не используйте @Transactional в контроллерах - это плохая практика. ✅ Решение 2: Fetch Join Подгрузите нужные данные сразу через JOIN FETCH: @Query("SELECT u FROM User u LEFT JOIN FETCH u.friends WHERE u.id = :id") Optional<User> findByIdWithFriends(@Param("id") Long id); 📌 Плюс: 1 запрос вместо N (N+1 проблема решается). 📌 Минус: может быть избыточная загрузка, особенно с большими коллекциями. ✅ Решение 3: DTO проекция Лучший способ в большинстве случаев - проецировать сразу в DTO: @Query(""" SELECT new com.example.UserDto(u.name, f.name) FROM User u LEFT JOIN u.friends f WHERE u.id = :id """) List<UserDto> findUserWithFriendNames(@Param("id") Long id); 📌 Выгружает только нужные данные. Быстро, безопасно, эффективно. Ленивая инициализация - ок, если вы контролируете границы транзакций. Проекции и fetch join - ваши лучшие друзья, если нужен контроль и производительность. 📲 Мы в MAX 👉@BookJava
880
11
📌 Java Collections 📲 Мы в MAX 👉@BookJava+2
📌 Java Collections 📲 Мы в MAX 👉@BookJava
949
12
🧠 Spring Boot: ленивые зависимости через ObjectProvider Иногда сервису не нужно всегда инжектить другую зависимость при стар
🧠 Spring Boot: ленивые зависимости через ObjectProvider Иногда сервису не нужно всегда инжектить другую зависимость при старте — только иногда по ходу работы. Но @Autowired всё равно тянет её сразу, даже если она вам пока не нужна. Это бьёт по времени старта и может вызвать циклические зависимости. 💡 Решение: использовать ObjectProvider<T>. Пример: @Service public class NotificationService { private final ObjectProvider<EmailSender> emailSenderProvider; public NotificationService(ObjectProvider<EmailSender> emailSenderProvider) { this.emailSenderProvider = emailSenderProvider; } public void sendEmailIfEnabled(String to, String body) { if (featureEnabled()) { EmailSender sender = emailSenderProvider.getIfAvailable(); if (sender != null) { sender.send(to, body); } } } } 📌 ObjectProvider: ▫️не создаёт бин сразу — ленивый доступ; ▫️ позволяет проверить наличие бина (getIfAvailable() / ifAvailable(...)); ▫️можно использовать stream() — для коллекций бинов. ⚠️ Это не альтернатива DI. Это способ контролировать создание и использование бинов вручную, когда это действительно нужно. 📈 Отлично помогает: ▫️при борьбе с циклическими зависимостями; ▫️для optional-бинов; ▫️чтобы ускорить старт приложения. 📲 Мы в MAX 👉@BookJava
1 216
13
💡 Чем опасен @Scheduled(fixedRate) без @Transactional? Расписание в Spring через @Scheduled — удобный способ запускать задач
💡 Чем опасен @Scheduled(fixedRate) без @Transactional? Расписание в Spring через @Scheduled — удобный способ запускать задачи по таймеру. Но часто разработчики забывают про транзакции, особенно с fixedRate, и попадают в ловушку. 📌 Пример проблемы: @Scheduled(fixedRate = 10_000) public void cleanUp() { List<Job> jobs = jobRepository.findAllByStatus(PENDING); jobs.forEach(job -> { job.setStatus(PROCESSING); jobRepository.save(job); }); } 🧨 Каждые 10 секунд метод запускается заново. Если выполнение предыдущего ещё не закончено, начнётся второй поток, который заберёт те же PENDING -записи. В итоге — дублирование обработки, гонки, повреждение данных. 📉 Особенно критично при долгих задачах или высокой нагрузке. ✅ Решение — обернуть метод в транзакцию + использовать блокировки: @Transactional @Scheduled(fixedRate = 10_000) public void cleanUp() { List<Job> jobs = jobRepository.findAllByStatusForUpdate(PENDING); // SELECT ... FOR UPDATE jobs.forEach(job -> { job.setStatus(PROCESSING); jobRepository.save(job); }); } 📌 Или добавить флаг “locked”, чтобы явно помечать взятые задачи. 💡 Лучше использовать @Scheduled(fixedDelay) — он ждёт завершения предыдущего запуска. Это безопаснее по умолчанию. 🧠 Подумайте о том, чтобы заменить @Scheduled на: * Spring Batch (если сложные джобы) * Spring Integration / Flowable / Camunda (если нужны гарантии и retry) * Quartz (если нужен контроль и очереди) 📲 Мы в MAX 👉@BookJava
981
14
🔴 Завтра тестовое собеседование с Java-разработчиком 2 сентября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собес
🔴 Завтра тестовое собеседование с Java-разработчиком 2 сентября(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Сергею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.
914
15
🔧 Maven vs. Gradle: что выбрать разработчику? Когда речь заходит о сборке Java-проектов, выбор обычно падает на два главных
🔧 Maven vs. Gradle: что выбрать разработчику? Когда речь заходит о сборке Java-проектов, выбор обычно падает на два главных инструмента: Maven и Gradle. Оба давно стали стандартом индустрии, но каждый имеет свои особенности. Разберёмся, что выбрать 👇 ☕ Maven — проверенная классика ✅ Строгая структура: легче читать и сопровождать ✅ Надёжность и предсказуемость сборки ✅ Большое комьюнити и множество плагинов ⚠️ XML-конфигурация громоздкая ⚠️ Медленнее по сравнению с Gradle ⚡ Gradle — гибкость и скорость ✅ Поддержка Kotlin и Groovy DSL ✅ Инкрементальные сборки и кэширование → быстрее ✅ Более гибкий подход к настройке ⚠️ Порог входа выше ⚠️ Иногда сложно отлаживать конфигурацию 💡 Вывод: * 🔹 Выбирай Maven, если важны стабильность, простота и читаемость. * 🔹 Выбирай Gradle, если хочешь максимум производительности и гибкости. 🎯 В крупных проектах Gradle становится всё популярнее, особенно при использовании Kotlin. Но в enterprise-среде Maven по-прежнему правит бал. 📲 Мы в MAX 👉@BookJava
870
16
🧠 Трюк с @Configuration и @ComponentScan: как не словить баг при миграции на Spring Boot 3+ Когда вы выносите конфигурацию в
🧠 Трюк с @Configuration и @ComponentScan: как не словить баг при миграции на Spring Boot 3+ Когда вы выносите конфигурацию в отдельный модуль или создаёте библиотеку с @Configuration-классами — не забывайте: 📌 Spring Boot 3+ по умолчанию НЕ сканирует пакеты вне стартового (main). Пример: // Внутри библиотеки @Configuration public class MyLibConfig { @Bean public MyService myService() { return new MyService(); } } И вы такие: @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } 🔥 Но MyService не создаётся! Почему? 💡 Потому что @ComponentScan по умолчанию сканирует ТОЛЬКО package текущего класса и ниже. 📌 Решения: 1. Ручной импорт конфигурации: @SpringBootApplication @Import(MyLibConfig.class) public class App { ... } 2. Сделать конфигурацию @AutoConfiguration и подключить через spring.factories или META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports — актуально для библиотек. 3. Переместить MyLibConfig в подпакет стартового класса (не всегда возможно или удобно). ⚠️ Часто баг проявляется неявно: контекст стартует, но бины "теряются", и вы получаете NoSuchBeanDefinitionException в рантайме. ✅ После миграции на Spring Boot 3+ обязательно проверьте, что нужные конфигурации действительно подхватываются. Особенно, если раньше они подключались "магически". 📲 Мы в MAX 👉@BookJava
835
17
🧠 Неочевидный performance-трюк с @Transactional(readOnly = true) Многие используют @Transactional(readOnly = true) просто по
🧠 Неочевидный performance-трюк с @Transactional(readOnly = true) Многие используют @Transactional(readOnly = true) просто по инерции. Но вы знали, что в Spring это влияет не только на семантику, но и на производительность? 📌 Что делает readOnly = true: * Подсказывает Hibernate, что внутри транзакции не будет изменений сущностей. * Это позволяет избежать затрат на грязную проверку (dirty checking). * Не создаётся snapshot состояний сущностей → меньше памяти и операций. 💡 Пример: @Transactional(readOnly = true) public List<User> findActiveUsers() { return userRepository.findByActiveTrue(); } ⚠️ А теперь важно: если вы случайно измените сущность в таком методе, Hibernate проигнорирует изменения — потому что readOnly намекает: "не трогай". 📉 В реальном приложении с большим количеством запросов к БД, особенно читающих, такой подход даёт ощутимый буст — меньше нагрузки на ORM, меньше GC, быстрее ответы. 📌 Где применять: * Методы только для чтения. * REST-эндпоинты GET. * Сервис-методы, возвращающие DTO и не модифицирующие Entity. ⚠️ Где не надо: * Методы с lazy-loading и последующими модификациями. * Там, где возможно случайное изменение Entity (например, через mapper'ы). 👉 Используйте @Transactional(readOnly = true) не как декор, а как инструмент для оптимизации. 📲 Мы в MAX 👉@BookJava
865
18
🧠 Spring Boot: правильно логируем @ExceptionHandler Сейчас покажу простой, но часто упускаемый момент при обработке ошибок в
🧠 Spring Boot: правильно логируем @ExceptionHandler Сейчас покажу простой, но часто упускаемый момент при обработке ошибок в Spring Boot. Если у вас есть глобальный @ExceptionHandler, убедитесь, что вы не теряете stacktrace при логировании. ❌ Плохо: @ExceptionHandler(MyException.class) public ResponseEntity<String> handle(MyException ex) { log.error("MyException occurred: {}", ex.getMessage()); // stacktrace теряется! return ResponseEntity.status(500).body("Error"); } ✅ Хорошо: @ExceptionHandler(MyException.class) public ResponseEntity<String> handle(MyException ex) { log.error("MyException occurred", ex); // stacktrace будет видно в логе return ResponseEntity.status(500).body("Error"); } 📌 log.error(String, Throwable) — правильный способ логировать исключения. Это позволяет: * Сохранять stacktrace для дебага; * Не терять вложенные причины (getCause()); * Работать с лог-агрегаторами (ELK, Grafana, etc). 💡 Если вы используете Slf4j и формат log.error("message: {}", ex.getMessage()), вы теряете почти всю полезную информацию об ошибке. ⚠️ И не забывайте: глобальные хендлеры — это хорошо, но не глушите все ошибки без разбора. Лучше создавать разные @ExceptionHandler под каждую категорию исключений. 📲 Мы в MAX 👉@BookJava
1 096
19
🧠 Spring Boot: как НЕ попасть в ловушку с @Scheduled и многопоточностью Когда используете @Scheduled для периодических задач
🧠 Spring Boot: как НЕ попасть в ловушку с @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
1 001
20
🚀 Подборка полезных 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
910