25698
Все самое полезное для Java-разработчика в одном канале. Список наших каналов: https://t.me/proglibrary/9197 Обратная связь: @proglibrary_feedback_bot По рекламе: @proglib_adv Прайс: @proglib_advertising
«Этот манёвр будет стоить нам 51 год...»
— или 20% от вашего бюджета на самообразование. В Java-мире архитектурные паттерны и алгоритмы — это то, что отличает мидла от сеньора. Не ждите особого случая, забирайте базу прямо сейчас.
Успейте купить курсы Proglib Academy по старой цене до понедельника:
— Разработка ИИ-агентов
— Математика для разработки AI-моделей
— ML для старта в Data Science
— Математика для Data Science
— Специалист по ИИ
— Алгоритмы и структуры данных
— Программирование на Python
— Основы IT для непрограммистов
— Архитектуры и шаблоны проектирования
Взять по старой цене
⚠️ Цены вырастут 19 января
🐸 Библиотека джависта
#DevLife
💻 Kafka транзакции в Spring Boot: от конфига до кода
Разберём практическую реализацию транзакций на конкретном примере.
1️⃣ Конфигурация продюсера
propertiesspring.kafka.producer.properties.enable.idempotence=true
spring.kafka.producer.properties.transactional.id=order-service-${random.value}-
propertiesspring.kafka.consumer.isolation-level=read_committed
@Bean
public KafkaTransactionManager<String, Object> kafkaTransactionManager(
ProducerFactory<String, Object> producerFactory
) {
return new KafkaTransactionManager<>(producerFactory);
}
@Transactional
public void publishOrderResult(OrderRequest request) {
String orderId = UUID.randomUUID().toString();
OrderPlacedEvent event = new OrderPlacedEvent(
orderId,
request.email(),
request.productName()
);
kafkaTemplate.send("order-placed", orderId, event);
kafkaTemplate.send("order-audit", orderId, event);
// Обе отправки атомарны — либо обе успешны, либо обе откатятся
}
@Primary
@Bean
public KafkaTransactionManager<String, Object> kafkaTransactionManager(...) {...}
@Transactional("kafkaTransactionManager")
public void publishOrderResult(...) {...}
🐸 Библиотека джависта
#DevLife
Roadmap для Java-разработчика: интеграция ИИ-агентов в Enterprise
ИИ-агенты — это не только область Python. В корпоративной разработке на Java архитектура и надёжность агентов выходят на первый план.
Ваш путь внедрения ИИ:
— изучение принципов взаимодействия с LLM через API;
— интеграция агентских паттернов в существующие `JVM`-сервисы;
— создание систем с разделением ответственности между агентами;
— мониторинг и отладка автономных процессов.
Курс «Разработка ИИ-агентов» даст необходимые навыки для проектирования интеллектуальных надстроек над сложными системами.
Повысить квалификацию в ИИ
При регистрации до 19 января действует акция «3 в 1»: один курс покупаете, два получаете в подарок.
Дедлайн: 19 января.
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
🐸 Библиотека джависта
#DevLife
❓ Как бы вы оптимизировали запрос с JOIN?
— Создание индексы на колонках, которые используются для соединений. Это ускорит поиск строк, особенно если соединяемые таблицы большие.
— Если возможно, уменьшить размер данных, участвующих в соединении. Для этого можно использовать подзапросы или фильтровать данные до соединения.
— Использование правильного типа JOIN.
— EXPLAIN для анализа выполнения запроса и выявления узких мест. Это покажет, как именно СУБД обрабатывает запрос и на каких этапах происходят замедления.
— Если запросы с JOIN используются часто, создать материализованные представления для хранения результатов, что снизит нагрузку на базу данных при повторных обращениях.
— Рассмотреть варианты изменения структуры БД (например, денормализация).
🐸 Библиотека собеса по Java
#core #лучшее2025
🐸 Библиотека джависта
#DevLife
⌛ Сохраняйте шпаргалку по командам git
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
🐸 Библиотека джависта
#DevLife
⚙️ Как работает Garbage Collector
Механизм сборки мусора в JVM — это не просто “магия, которая чистит память”, а сложная система, работающая по поколениям, фазам и стратегиям.
Понимание его внутренней архитектуры важно, если вы хотите управлять производительностью, избегать утечек и эффективно настраивать параметры JVM.
🔹 Архитектура: как устроена куча (Heap)
Куча памяти делится на поколения:
Heap
├── Young Generation
│ ├── Eden Space
│ └── Survivor Spaces (S0, S1)
└── Old Generation (Tenured)
🐸 Библиотека джависта
#DevLife
😮 Топ-вакансий для джавистов за неделю
Backend Engineer (Java/Kotlin) — от 600 до 3 500 $ — офис (Минск)
Middle Java-разработчик — 240 000 - 260 000₽ — удалёнка
Java Developer — от 5 000 $ — удалёнка
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
🔥 Field vs Constructor Injection: зомби-объекты в production
Казалось бы, избитая тема. Но копните глубже @Autowired — и обнаружите, что ваши объекты после new существуют в состоянии "клинической смерти".
Автор разбирает не "удобство тестов" (это мелочи), а фундаментальные проблемы: нарушение контракта конструктора, проблемы с JMM, хрупкость при AOT-компиляции для GraalVM, race conditions в мультипоточке.
Рекомендую прочитать, если хотите понять почему Spring Framework 6 окончательно выбрал constructor injection, а не просто "так все делают".
🔗 Читайте подробнее
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#coreJava
🔍 Просто о сложном: идемпотентность
Идемпотентность — это свойство операции, которую можно выполнить несколько раз, получая тот же результат, что и при однократном выполнении.
Простыми словами: повторный вызов не меняет состояние системы после первого успешного выполнения.
Классический пример — HTTP методы: GET, PUT, DELETE идемпотентны, POST — нет.
🔹 Ключевые моменты
▪️ Идемпотентная операция: setStatus(ACTIVE) — сколько раз ни вызови, статус будет ACTIVE.
▪️ Неидемпотентная операция: balance += 100 — каждый вызов увеличивает баланс.
▪️ Идемпотентность ≠ отсутствие побочных эффектов (это чистота функций).
▪️ Критична для распределённых систем: retry-механизмы, очереди сообщений, API.
▪️ Защищает от дублирующих запросов при сетевых сбоях.
🔹 Под капотом
В реальных системах идемпотентность достигается через:
→ Idempotency Key — клиент генерирует уникальный ключ и передаёт в запросе. Сервер проверяет: если операция с таким ключом уже выполнялась — возвращает закешированный результат.
→ Версионирование — оптимистичные блокировки через версии записей (JPA @Version).
→ Уникальные идентификаторы — вместо "создай заказ" отправляем "создай заказ с ID=xyz". Повторный запрос с тем же ID игнорируется.
→ Статус-машины — переходы между состояниями: если уже в целевом состоянии, ничего не делаем.
🔹 Подводные камни
— Idempotency key нужно хранить ограниченное время (обычно 24 часа).
— Нужна атомарность проверки и выполнения.
— Сложность при асинхронной обработке.
— Не все бизнес-операции можно сделать идемпотентными.
— Overhead на хранение и проверку ключей.
✔️ Когда использовать
— REST API с критичными операциями (платежи, создание заказов).
— Kafka consumers — защита от повторной обработки при rebalance.
— Интеграция с внешними системами через retry.
— Scheduled jobs, которые могут запуститься дважды.
— Распределённые транзакции (Saga pattern).
— Webhook обработчики.
— Любые операции с денежными средствами.
❌ Не нужно:
— Внутренние CRUD операции без side effects.
— Операции чтения (они идемпотентны по умолчанию).
— Высоконагруженные операции, где overhead критичен.
— Простые внутренние методы без внешних вызовов.
🔧 Бонус-трюк: в Spring можно создать аннотацию @Idempotent и реализовать через AOP с использованием Redis для хранения idempotency keys. Получается декларативная идемпотентность на уровне методов.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
🖥 Когда Kafka транзакции действительно нужны
Kafka транзакции не панацея, а узкоспециализированный инструмент.
🔹 Что гарантируют Kafka транзакции:
— Атомарную публикацию в несколько топиков (все сообщения видны или ни одно).
— Связывание read → process → write в одну операцию для консьюмеров-продюсеров.
🔹 Что НЕ гарантируют:
— Откат изменений во внешних системах (БД, API, email).
— Защиту от дубликатов, если downstream-сервисы не настроены правильно.
🔹 Два реальных сценария использования транзакций:
1️⃣ Публикация в несколько топиков без возможности дедупликации
Отправка события обработки заказа и событие в audit-топик с временной меткой. Если сервис упадёт между отправками, то при повторе время не совпадёт — история будет некорректной.
Транзакция гарантирует, что оба сообщения либо станут видимы консьюмерам одновременно, либо ни одно из них не будет доставлено.
2️⃣ Схема read → process → write без дедупликации
Если сервис упадёт после отправки сообщений, но до коммита оффсета, downstream-сервисы увидят дубликаты.
Транзакции связывают отправку и коммит в одну атомарную операцию.
💡 Ключевой вывод: большинство систем прекрасно работают без транзакций, используя дедупликацию и идемпотентность.
Транзакции добавляют накладные расходы и подходят только для специфических кейсов.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
❓ Что такое JIT-компилятор?
JIT (Just-In-Time) компилятор — это компонент JVM, который компилирует байт-код в машинный код непосредственно во время выполнения программы, а не до старта приложения. Его задача — улучшить производительность, оптимизируя код, исходя из реальных условий работы программы.
JIT компилирует только те части кода, которые реально исполняются, и может применять различные оптимизации для ускорения работы приложения. Это позволяет сочетать гибкость интерпретируемого байт-кода и производительность нативного кода.
🐸 Библиотека собеса по Java
#core
⌛ Как настроить production-ready логирование в Spring Boot
Логи в проде — это не просто System.out.println(). Это структурированные данные, correlation ID, асинхронная запись и ротация. Разбираем настройку от А до Я.
1️⃣ Выбираем стек: Logback + SLF4J
Spring Boot из коробки использует Logback. Добавляем зависимости:
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
ИЛИ
gradleimplementation 'net.logstash.logback:logstash-logback-encoder:7.4'
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeContext>false</includeContext>
<includeMdc>true</includeMdc>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
@Component
public class CorrelationIdFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String correlationId = request.getHeader("X-Correlation-ID");
if (correlationId == null) {
correlationId = UUID.randomUUID().toString();
}
MDC.put("correlationId", correlationId);
response.setHeader("X-Correlation-ID", correlationId);
try {
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
logging:
level:
root: INFO
com.yourcompany: DEBUG
org.springframework.web: WARN
org.hibernate.SQL: DEBUG
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
</appender>
<root level="INFO">
<appender-ref ref="ASYNC_FILE"/>
</root>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>logstash.example.com:5000</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
👑 Магия IntelliJ IDEA: покрытие тестами
Запускаешь тесты, они зелёные, и ты думаешь всё ок? А потом баг на проде в ветке, которую никто не проверил. IDEA умеет показывать, что реально покрыто тестами.
🔹 Что это
Run with Coverage — запуск тестов с визуализацией покрытия кода. Видишь прямо в редакторе, какие строки покрыты тестами, а какие нет.
🔹 Как запустить
— Ctrl+Shift+F10 → выбрать "Run with Coverage".
— Или правой кнопкой на тест/класс → "More Run/Debug" → "Run with Coverage".
— Или через иконку щита рядом с кнопкой Run.
🔹 Что показывает
→ Зелёная полоска слева от кода — строка выполнилась.
→ Красная полоска — строка не покрыта тестами.
→ Жёлтая полоска — ветка покрыта частично (if выполнился, else — нет).
→ Окно Coverage — статистика по классам, пакетам, методам.
🔹 Фишки
→ Кликни на класс в Coverage window → увидишь его code coverage.
→ Кликни на жёлтую полоску → IDEA покажет, какая именно ветка не покрыта.
→ Сортируй классы по проценту покрытия — найдёшь слабые места.
→ Экспортируй отчёт (HTML) через кнопку в Coverage панели.
🔹 Зачем это нужно
— Находишь непокрытые edge cases.
— Видишь, что тест не проверяет все ветки if/else.
— Не гадаешь, а точно знаешь, что покрыто.
— Быстро понимаешь, где добавить тесты.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
⚡️ Параллельные стримы: ускорение или нет?
Java предоставляет мощный инструмент для обработки данных — параллельные стримы. Они позволяют автоматически распределять вычисления по нескольким потокам, но их эффективность зависит от множества факторов.
Добавление parallelStream() бездумно — это не "оптимизация", а лотерея с шансом на баги и падение.
❌ Когда не использовать
— При небольшом наборе данных (<10 000 элементов) затраты на управление потоками могут превышать прирост скорости.
— Операции sorted(), distinct() или limit() требуют полного знания данных, что снижает эффективность параллельного выполнения.
— Вложенные parallelStream() в CompletableFuture или ExecutorService могут привести к конкуренции за ресурсы и неожиданному падению производительности.
✔️ Когда использовать
— Обработка больших объёмов данных (100 000+ элементов).
— Операции независимы и ресурсоёмки, например, сложные вычисления, парсинг файлов, загрузка данных из сети.
🔍 Важная особенность
parallelStream() использует ForkJoinPool.commonPool(). Если есть другие задачи, использующие этот же пул, они могут начать конкурировать за потоки, замедляя всё приложение.
💬 Делитесь в комментах интересными кейсами
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava #лучшее2025
📈 Как «ленивая разработка» захватывает IT-рынок
Пока мы выстраиваем архитектуру, пишем тесты и спорим о лучших практиках, рынок всё активнее обживают те, кто вообще не пишет код. Low-code и no-code решения не просто живы — они становятся нормой для бизнеса.
Порог входа минимальный, скорость разработки — бешеная, а заказчику всё равно, написано ли это на Java или накликано в визуальном редакторе. Вопрос: как долго останется актуальной классическая разработка?
🔗 Подробнее в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava #лучшее2025
Enterprise AI 2026: время автономных Java-агентов
В мире Spring и Hibernate наступает новая эра — эпоха мультиагентных систем. В 2026-м ИИ-агенты становятся частью бизнес-логики крупных корпораций.
Освойте передовой стек на нашем курсе:
— паттерн ReAct: внедрение автономности в сложные системы;
— интеграция с n8n для бесшовной автоматизации процессов;
— протокол MCP: стандарт взаимодействия агентов в Enterprise;
— продвинутый RAG: работа с огромными объёмами корпоративных данных.
Сделайте шаг в сторону ИИ, пока другие только присматриваются.
❄️ До 12 января акция «3 в 1»: курс по ИИ-агентам + 2 курса в подарок.
Изучить программу
💼⌛️ ТОП-5 причин, почему программист не может долго найти работу
Почему некоторые разработчики остаются "между работами" месяцы?
Не всегда дело в нехватке вакансий или «рынок просел». Часто дело в подходе к поиску проекта. Вроде бы есть опыт, стек, даже pet-проекты, но офферов всё нет.
Часто корень проблемы — неумение продать себя правильно. Отказ выполнять тестовые задания, считая их ненужными или обидными. Кроме того, нежелание рассматривать стажировки как стартовую площадку для получения опыта и расширения профессиональных связей также может замедлить процесс трудоустройства. И это далеко не все возможные причины.
🔗 Подробнее в статье
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava #лучшее2025
👑 Магия IntelliJ IDEA: Ctrl+E
Переключаешься между файлами через Project View? Теряешь время на поиск нужной вкладки среди десятка открытых? Есть способ быстрее.
🔹 Что это
Ctrl+E (Recent Files) — показывает список недавно открытых файлов. Быстрый доступ к тому, с чем ты работал последние 5-10 минут.
🔹 Что умеет
— Показать последние открытые файлы.
— Переключиться на файл по первым буквам названия.
— Видеть структуру директорий для контекста.
— Отметить часто используемые файлы звёздочкой.
— Фильтровать список прямо в окне поиска.
🔹 Зачем это нужно
— Не нужно искать файл в дереве проекта.
— Быстрее, чем кликать по вкладкам.
— Видишь историю своей работы.
— Меньше отвлекаешься от кода.
🎯 Бонус
— Нажми Ctrl+E дважды — увидишь только недавно редактированные файлы.
— Начни печатать — список отфильтруется автоматически.
— Стрелками вверх/вниз быстро переключаешься между последними 2-3 файлами.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
😮 Топ-вакансий для джавистов за неделю
Java Developer — офис (Москва)
Java Developer (Middle) — 100 000 – 200 000 ₽ — офис (Тольятти)
Java-разработчик — 300 000 — 490 000 ₽ — офис/Гибрид (Москва)
➡️ Еще больше топовых вакансий — в нашем канале Java jobs
Java в мире AI-агентов: Enterprise-подход к автономности
Пока другие балуются с промптами, мы учимся строить надёжные мультиагентные системы. В 2026 году автономные агенты — это стандарт для автоматизации сложных бизнес-процессов.
На курсе от Proglib Academy ты освоишь:
— паттерн ReAct: как заставить агента рассуждать и действовать;
— интеграцию с n8n для управления рабочими процессами;
— протокол MCP от Anthropic для бесшовного обмена данными;
— продвинутый RAG для мгновенного поиска по корпоративным знаниям.
Результат — дипломный проект в виде автономной группы агентов для анализа данных или техподдержки.
❄️ До 12 января забирай курс по ИИ-агентам по акции «3 в 1» (получи ещё два курса бесплатно).
Прокачать скиллы
📈 Big-O ≠ производительность
Часто выбор коллекции ограничивается только таблицей сложностей и на этом всё.
Но реальный кейс сложнее: средняя сложность ≠ реальная скорость в продакшне. JVM, кэш процессора, GC и паттерны доступа могут радикально поменять картину.
🔑 Главная мысль
Выбирайте коллекцию под сценарий использования, а не “по самой быстрой ячейке в таблице”.
1️⃣ ArrayList — быстр в чтение, но не во вставке
ArrayList хранит элементы в массиве → локальность памяти + CPU кэш → итерации летят.
Вставка в середину за O(n), но при небольших списках разница с LinkedList исчезающе мала.
🔧 Паттерн использования:
— 90% чтение, редкие вставки → идеально.
— Если заранее известно примерное кол-во элементов → задайте initialCapacity, иначе ArrayList будет несколько раз пересоздавать массив (copy O(n) на каждом росте).
📌 Факт:
В бенчмарках JMH даже при вставке в середину ArrayList часто быстрее LinkedList просто потому, что LinkedList платит за “pointer chasing” (скачки по памяти, cache-miss).
2️⃣ LinkedList — звучит круто, но редко нужен
Да, вставка/удаление в начало или конец за O(1).
Но get(i) = O(n), и каждый шаг = новый объект, новая ссылка → нагрузка на GC.
🔧 Паттерн использования:
— Когда нужна двусторонняя очередь с частыми удалениями/добавлениями в начало и конец.
— Во всех остальных случаях лучше ArrayDeque, он без лишних объектов и быстрее почти всегда.
📌 Факт:
LinkedList ест больше памяти: на каждый элемент два указателя + объект-узел.
3️⃣ HashMap / HashSet — быстрые, пока не наступил resize
HashMap даёт O(1) доступ при хорошем hashCode().
Но:
— Если хэши “плохие” → коллизии → O(log n)
— При достижении load factor 0.75 → resize → перераспределение всех бакетов (дорогая операция).
🔧 Паттерн использования:
— Когда нужен быстрый поиск по ключу без сохранения порядка или когда важно хранить уникальные элементы или строить словари/кэши по ключу.
— Если знаете примерное кол-во элементов → сразу задайте кол-во элементов в конструкторе new HashMap<>(N).
📌 Факт:
Начиная с Java 8 при коллизии, когда LinkedList становится длинным (по умолчанию ≥ 8 элементов) → список превращается в красно-чёрное дерево.
4️⃣ TreeMap / TreeSet — порядок стоит денег
Дают O(log n) доступ и всегда хранят ключи отсортированными.
Но если сортировка нужна редко, дешевле собрать HashMap и вызвать sorted() на стриме.
🔧 Паттерн использования:
— Когда важно поддерживать сортировку на каждой операции (напр. Top-N задач в приоритетной очереди).
— Не храните mutable-ключи, т.к. можно “потерять” элемент при изменении поля, участвующего в compareTo.
📌 Факт:
TreeMap хранит узлы с балансировкой (красно-чёрное дерево) → накладные расходы на память + сравнения ключей.
5️⃣ LinkedHashMap — скрытый герой для кэшей
LinkedHashMap поддерживает порядок вставки или порядок доступа (accessOrder=true).
Можно сделать LRU-кэш, переопределив removeEldestEntry.
🔧 Паттерн использования:
— Когда важен порядок, но сортировка не нужна.
— Когда нужно легко реализовать ограниченный кэш.
📌 Факт:
Каждый get() в режиме accessOrder вызывает перестановку в двусвязном списке → небольшие накладные расходы.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava #лучшее2025