bookjava | Unsorted

Telegram-канал bookjava - Библиотека Java разработчика

10986

📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP

Subscribe to a channel

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

Есть фича. Есть дедлайн. Есть понимание, что тесты надо писать… но они отъедают время, которого итак впритык.

Один наш знакомый девелопер сказал: «С тех пор как поставил Explyt Test — начал писать меньше тестов… но покрытие стало лучше. Как это вообще возможно?!»

Попробуйте сами. Плагин сам предлагает тесты для вашего кода — прямо в IDE.
👉 explyt.ai — сэкономь себе пару часов уже сегодня.

Читать полностью…

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

📌 Ошибка: Вызов метода с @Transactional внутри того же класса не запускает новую транзакцию.

Почему? Spring оборачивает бин в прокси, а внутренние вызовы проходят мимо прокси, значит, аннотация игнорируется.

Пример проблемы:


@Service
public class OrderService {

@Transactional
public void createOrder() {
saveOrder();
}

@Transactional
public void saveOrder() {
// Новый транзакционный контекст не создастся!
}
}


💡 Как правильно:
1. Вынести saveOrder() в отдельный бин.
2. Или получить прокси текущего бина через AopContext:


@Service
@EnableAspectJAutoProxy(exposeProxy = true) // важно!
public class OrderService {

@Transactional
public void createOrder() {
((OrderService) AopContext.currentProxy()).saveOrder();
}

@Transactional
public void saveOrder() {
// Теперь всё ок ✅
}
}


⚠️ Важный момент: exposeProxy = true нужен на уровне конфигурации, иначе AopContext не заработает.


Понимание этой тонкости критично для корректного управления транзакциями в Spring! 🚀

👉@BookJava

Читать полностью…

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

Сегодня покажу вам 🧠 один тонкий момент в работе с Optional, который часто ловит даже опытных.

Многие пишут так:


Optional<String> optional = getValue();
if (optional.isPresent()) {
doSomething(optional.get());
}


⚠️ Это антипаттерн! Вы теряете суть Optional и рискуете ошибками в многопоточке.

📌 Правильный способ — использовать функциональный стиль:


getValue().ifPresent(this::doSomething);


Или ещё элегантнее:


getValue()
.map(this::transform)
.filter(this::isValid)
.ifPresent(this::doSomething);


💡 Подходы:
- map для преобразования значения
- filter для отсеивания ненужных
- orElse, orElseGet, orElseThrow для обработки отсутствия
- ifPresentOrElse в Java 9+ для двух вариантов действий

📈 Выгоды:
- Код становится компактнее
- Безопаснее при рефакторинге
- Лучше для чтения в потоковых операциях (Stream API)

🛠 Если нужно вынуть значение — используйте orElseThrow() вместо .get():


String value = getValue().orElseThrow(() -> new IllegalStateException("Value not found"));


👉 Отказывайтесь от .isPresent() и .get() связки — используйте силу функционального подхода! 🚀

👉@BookJava

Читать полностью…

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

🧠 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 — он не так прост, как кажется.

👉@BookJava

Читать полностью…

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

👩‍💻 Разработка на Java требует глубокого понимания не только языка, но и принципов работы JVM, многопоточности и современных фреймворков.

Курс «Java Developer. Professional» — это структурированное обучение для разработчиков, которые хотят выйти на новый уровень, освоить актуальный стек технологий и уверенно претендовать на позиции уровня Middle+.

🦾 Вы получите 96 часов практической работы, обучение на живых вебинарах, вы разберете ключевые аспекты работы JVM, научитесь строить эффективные многопоточные приложения, освоите Spring WebFlux, Kafka, реактивный Postgres и Kubernetes.

Программа OTUS постоянно обновляется, соответствуя требованиям рынка, а диплом ценится работодателями.

👉 Пройдите вступительное тестирование и присоединяйтесь к группе: https://vk.cc/cL3cnt

🎁 Начните обучение со скидкой, подробности у менеджеров. ПРОМОКОД: JAVA_04

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Читать полностью…

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

🧠 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() уже безопасно очищает контекст.

💡 Эта ошибка особенно коварна, потому что не всегда проявляется — зависит от настроек, триггеров в БД, кэша и т.д.

👉@BookJava

Читать полностью…

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

🧠 Spring Boot и медленные autowire — проверь, не зарыта ли у тебя бомба в @Configuration

Есть распространённый анти-паттерн: ты используешь @Configuration и внутри создаёшь бины с @Bean, а в этих методах — инжектишь зависимости через параметры. Всё выглядит красиво и «по фэншую»... но только на первый взгляд.


@Configuration
public class MyConfig {

@Bean
public MyService myService(SomeDep dep) {
return new MyService(dep);
}

@Bean
public SomeDep someDep() {
return new SomeDep();
}
}


⚠️ Проблема: такие методы вызываются при старте контекста, и если SomeDep создаётся долго (например, подтягивает настройки из удалённого конфига, делает init-запрос в БД, или тянет секьюрити-контекст), это тормозит весь старт.

📌 Хуже всего, если ты не подозреваешь об этом: ведь @Bean -методы не видны как "инициализация", и кажется, что контекст тормозит "где-то ещё".

💡 Совет:
- Используй @Lazy в нужных местах, особенно если bean тяжёлый или редко используется.
- Разделяй конфигурацию: отдельно core, отдельно init-heavy.
- Не бойся отказаться от @Configuration в пользу @Component + @Service, если это упрощает понимание.

И главное — профилируй старт. spring-boot-starter-actuator + --debug могут открыть глаза.

👉@BookJava

Читать полностью…

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

🧠 Spring Boot 3.2+: ускоряем стартап с помощью application.metrics.export.observation.enabled=false

Spring Boot 3.2 по умолчанию включает сбор Micrometer Observation метрик — даже если вы не используете Prometheus, Datadog и пр.
Это полезно, но часто избыточно — особенно в микросервисах, где важна скорость старта.

📌 Что это даёт?

- Отключает автоконфигурацию ObservationRegistry
- Убирает связанные Bean
- Сокращает время старта до 30-60% (в зависимости от контекста)

💡 Как применить?

В application.yml или application.properties:


management:
metrics:
export:
observation:
enabled: false


Или так, если используешь .properties:


management.metrics.export.observation.enabled=false


⚠️ Важно: это не отключает другие метрики Micrometer.
Это касается только новой подсистемы Observation — она полезна для трассировки, но не всегда нужна.

📎 Документация Micrometer Observation

👉@BookJava

Читать полностью…

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

Реальные проекты и нетворкинг с профи: Летняя школа бэкенд‑разработки Яндекса открыла набор

Начинающие бэкендеры, есть планы на лето? Если уже умеете писать читаемый код в Python, Java или C++ и разбираетесь в алгоритмах, Летняя школа бэкенда Яндекса — ваш шанс прокачаться в разработке высоконагруженных сервисов. Вы получите уникальный опыт, работая вместе с ведущими специалистами компании.

Как проходит обучение:
со 2 июня по 27 июля — онлайн-лекции, семинары и практические задания
с 28 июля по 24 августа — разработка реальных проектов офлайн или онлайн

Вас ждут:
— работа в фулстек-командах в коворкингах Яндекса
— лекции от специалистов компании в летнем лектории
возможность стать частью команды и получить офер: больше половины выпускников становятся стажерами или сотрудниками компании

Школа бесплатная, но нужно пройти отбор. Отправляй заявку до 27 апреля!

Читать полностью…

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

Хотите глубже разобраться в функциональном программировании и писать более качественный код на Scala? Приходите на вебинар в Otus

24 апреля в 20:00 пройдёт открытый вебинар с Алексеем Воронцом — руководителем разработки в Naumen, 14 лет опыта, из них 9 лет на Scala. На практических примерах он покажет:

— почему Scala — функциональный язык
— как работать с ключевыми библиотеками
— как повысить выразительность кода

❗️ Если вы уже знакомы со Scala или только начинаете к нему присматриваться и хотите развивать функциональный подход в своих проектах — этот вебинар для вас.

Каждый участник:
— сможет задать вопросы эксперту
— получит скидку на полный курс по Scala-разработке

👉 Регистрируйтесь и сделайте свой код лучше

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Читать полностью…

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

🧠 Как ускорить загрузку контекста Spring Boot — простой приём

Если у вас тяжёлый Spring Boot-приложение с кучей конфигураций и бинов, время старта может легко вырасти до 20–30 секунд и больше. Сегодня покажу приём, который помогает ускорить cold start за счёт отключения ненужных автоматических конфигураций.

📌 Spring Boot автоконфигурация — это палка о двух концах.
Она упрощает старт, но часто тянет за собой кучу лишнего. Особенно если вы используете @SpringBootApplication, которая включает в себя @EnableAutoConfiguration.

💡 Решение — использовать spring.autoconfigure.exclude, чтобы явно выключить ненужное. Например:


# application.yaml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration


❗️Это особенно актуально:
- в микросервисах без UI (отключаем MVC)
- если datasource создаётся вручную
- в тестах и lightweight-режимах

👀 Как понять, что мешает?
1. Запусти приложение с флагом --debug или логгером org.springframework.boot.autoconfigure уровня DEBUG.
2. Посмотри, какие автоконфигурации "matched", но тебе не нужны.
3. Добавь их в exclude.

🧰 Альтернатива — использовать аннотацию @ImportAutoConfiguration с явным списком нужных автоконфигураций. Это тонкая настройка, идеально для библиотек и SDK.

⚠️ Не переусердствуй: отключение нужной конфигурации может привести к тихим багам. Лучше вырезать по одной и смотреть на эффект.

👉 Это один из способов сделать Spring Boot предсказуемым и быстрым, особенно в CI/CD или serverless-окружениях.

👉@BookJava

Читать полностью…

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

💡 Ленивая инициализация бинов в Spring Boot — мощный инструмент ускорения старта

По умолчанию Spring инициализирует все singleton-бины при запуске приложения. Это может быть проблемой в больших проектах: старт медленный, а половина бинов не нужна сразу.

📌 Как ускорить старт и снизить потребление памяти? — Lazy Init!

✅ Глобально:


spring:
main:
lazy-initialization: true


Все бины станут ленивыми — создадутся только при первом обращении. Это может сократить старт приложения на 30-60%!

✅ Локально (избирательно):


@Component
@Lazy
public class HeavyBean {
public HeavyBean() {
System.out.println("HeavyBean init...");
}
}


Или через @Lazy на зависимостях:


@Service
public class MyService {
public MyService(@Lazy HeavyBean heavyBean) {
this.heavyBean = heavyBean;
}
}


🧠 Когда использовать:

- В dev-окружении — чтобы ускорить локальный dev cycle.
- В CLI/Batch-приложениях, где используется 1-2 бина.
- Когда есть тяжёлые бины, не нужные на старте (например, интеграции, большие клиенты и т.п.).

⚠️ Осторожно:

- Если забыть @Lazy на зависимостях, Spring всё равно создаст бин.
- Некоторые бины должны быть загружены сразу (например, @Scheduled, @EventListener), иначе они не сработают.

👉@BookJava

Читать полностью…

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

🧠 ThreadLocal — скрытая угроза утечек памяти

ThreadLocal — удобный способ хранить данные, привязанные к потоку. Например, для SimpleDateFormat или текущего пользователя в рамках запроса. Но с ним легко получить утечку памяти, особенно в thread pool'ах.

📌 Почему?
ThreadLocal-хранилище (Thread.threadLocals) живёт столько же, сколько поток. А потоки из пулов живут долго. Если ты забыл вызвать remove() — данные останутся в памяти навсегда.

Пример:


private static final ThreadLocal<UserContext> context = ThreadLocal.withInitial(UserContext::new);

public void handleRequest() {
try {
context.set(new UserContext("user123"));
// работа с контекстом
} finally {
context.remove(); // ОБЯЗАТЕЛЬНО!
}
}


⚠️ Что пойдёт не так без remove()?

- Поток из пула закончит обрабатывать запрос, но UserContext останется висеть в ThreadLocalMap этого потока.
- Если UserContext содержит ссылки на другие объекты (например, HttpSession, EntityManager и т.д.) — вся эта цепочка не будет GC-шиться.
- И так накапливается утечка.

💡 Советы:

- Всегда вызывай remove() в finally.
- Для Spring можно использовать RequestScope или @ControllerAdvice вместо ThreadLocal.
- Проверяй код сторонних библиотек, если они используют ThreadLocal, особенно в фильтрах и интерсепторах.

👉@BookJava

Читать полностью…

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

❓ Разработчики, интересуетесь стримингом, хайлоадом и видеотехнологиями?

⏰ 22 апреля на митапе VK Видео техлиды и топ-менеджеры расскажут, как, например, устанавливают CDN.

Если вы бэкендер, мобильный разработчик или работаете с ML — будет много полезных кейсов из продакшена и возможность задать вопросы тем, кто строит крупнейшую видеоплатформу.

🎯 Узнаете, как устроена архитектура VK Видео, как выстроены команды и какие задачи сейчас в приоритете.

👉Загляните под капот VK Видео

Читать полностью…

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

Остался всего 1 день, чтобы прокачать асинхронный код на Scala Future 📢

15 апреля в 18:30 пройдёт открытый вебинар с Валентином Шилиным — старшим программистом и аналитиком данных Deutsche Telekom IT GmbH, экспертом по большим данным и преподавателем курсов по Scala и Apache Spark. Он расскажет:

— как избегать типичных ошибок (блокировки и потерю контекста)
— как комбинировать асинхронные операции (Future.sequence, traverse, for-comprehensions)
— как ускорить и упростить написание кода на Scala

❗️ Если вы хотите перейти с Java на Scala или уже используете Play Framework, Akka или Spark — на вебинаре вы узнаете, как грамотно писать асинхронный код и устранять «подводные камни».

Каждый участник:
— сможет задать вопросы эксперту
— получит скидку на полный курс по Scala-разработке

👉 Не упустите шанс перейти на новый уровень — регистрируйтесь, остался 1 день

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Читать полностью…

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

🧠 Сегодня покажу вам полезный трюк для 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 аннотации на контроллере валидация параметров работать не будет!

👉@BookJava

Читать полностью…

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

🚀 Подборка 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 разработчика

🤖 Хотите автоматизировать инфраструктуру для тестирования прямо в Gradle?

На открытом уроке «Облако в кармане: запускаем всю инфраструктуру для теста при сборке» от OTUS мы расскажем, как избежать ручных настроек и запусков. Вместо этого вы научитесь автоматизировать весь процесс с помощью Docker, DockerCompose и TestContainers, интегрируя их с Gradle.

Урок полезен для разработчиков на Kotlin и Java, которые работают с автотестами — интеграционными и end-to-end.

В ходе урока вы освоите:
▫️Автоматический запуск всей необходимой инфраструктуры для тестирования.
▫️Создание Docker-образов для тестов и деплоя.
▫️Разработку автотестов, которые поднимут ваши навыки на новый уровень.

Участники получат скидку на курс «Kotlin Backend Developer. Professional».

➡️ Встречаемся 29 апреля в 20:00 МСК, регистрация открыта: https://vk.cc/cL78v6

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Читать полностью…

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

🧠 Как избежать 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 или подзапросы.

👉@BookJava

Читать полностью…

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

Чем отличаются 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 — ошибки в логике, ответственность программиста.

👉@BookJava

Читать полностью…

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

Осталось всего 2 дня — углубитесь в функциональное программирование на Scala в Otus 📢

24 апреля в 20:00 пройдёт открытый вебинар с Алексеем Воронцом — руководителем разработки в Naumen, 14 лет опыта, из них 9 лет на Scala. Он расскажет:

— почему Scala — функциональный язык
— как работать с ключевыми библиотеками
— как повысить выразительность кода

Если вы уже знакомы со Scala или желаете перейти на него и хотите развивать функциональный подход в своих проектах — этот вебинар для вас.

Каждый участник:
— сможет задать вопросы эксперту
— получит скидку на полный курс по Scala-разработке

👉 Не упустите возможность перейти на новый уровень — регистрируйтесь, осталось 2 дня до начала

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Читать полностью…

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

23 апреля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.

Как это будет:
📂 Илья Аров, старший разработчик в Т1, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Илья будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Илье

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. 

Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot

Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2Vtzqvv6bu4

Читать полностью…

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

🧠 Lazy Initialization по-взрослому: не создавай проблемы на ровном месте

В Spring Boot часто можно встретить вот такую конструкцию:


@Service
public class EmailService {
private final SmtpClient client = new SmtpClient(); // дорогая инициализация
}


⚠️ Проблема: SmtpClient создаётся сразу при старте приложения. Даже если EmailService ни разу не вызовется. Это не только waste of resources, но и может сломать запуск, если SmtpClient требует специфического окружения.

📌 Решение — ленивая инициализация, но не через старый добрый null-check, а красиво, безопасно и читаемо:

💡 Способ #1: Lazy<T> wrapper


@Component
public class EmailService {
private final Supplier<SmtpClient> client = Suppliers.memoize(SmtpClient::new);

public void sendEmail(...) {
client.get().send(...);
}
}


Можно и без Guava:


public class Lazy<T> {
private Supplier<T> supplier;

public Lazy(Supplier<T> supplier) {
this.supplier = () -> {
T value = supplier.get();
this.supplier = () -> value;
return value;
};
}

public T get() {
return supplier.get();
}
}


💡 Способ #2: через Spring


@Service
public class EmailService {
private final ObjectProvider<SmtpClient> client;

public EmailService(ObjectProvider<SmtpClient> client) {
this.client = client;
}

public void sendEmail(...) {
client.getObject().send(...);
}
}



🧵 Итог:
- Не инициализируй тяжёлые объекты зря.
- Используй Supplier, ObjectProvider или Lazy<T>.
- Это особенно критично для тестов, лямбд и кэширования.

👉@BookJava

Читать полностью…

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

🧠 Сейчас покажу баг, который легко пропустить при работе с @Transactional в Spring Boot 3+.

📌 Проблема — транзакция не работает, потому что метод вызывается изнутри того же класса.

Рассмотрим пример:


@Service
public class UserService {

@Transactional
public void createUser(User user) {
saveUser(user);
sendWelcomeEmail(user); // бросает исключение
}

public void saveUser(User user) {
userRepository.save(user);
}
}


💥 Если sendWelcomeEmail выбросит исключение — транзакция не откатится, потому что @Transactional работает через прокси. Вызов createUser() должен идти извне, чтобы Spring "знал", что нужно обернуть вызов в транзакцию.


Решения:

1. Вынести transactional-метод в отдельный бин:

@Service
public class UserCreationService {
@Transactional
public void createUser(User user) {
// ...
}
}


2. Внедрить self-прокси:

@Autowired
private UserService self;

public void externalCaller(User user) {
self.createUser(user);
}


3. Использовать AopContext:

((UserService) AopContext.currentProxy()).createUser(user);

⚠️ Не забудь включить exposeProxy = true в @EnableAspectJAutoProxy.


💡 Современный подход — разделение ответственности: transactional-методы живут в отдельных сервисах, их проще тестировать и не возникает подобных ловушек.

👉@BookJava

Читать полностью…

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

🧠 Простое ускорение @Transactional методов в Spring Boot

Знаете, что @Transactional по умолчанию оборачивает метод в прокси?

Это значит:
- Внутренние вызовы в том же классе не проходят через транзакцию;
- Каждый такой прокси — это AOP-магия, которую можно обойти ради производительности.

📌 Если вы точно знаете, что метод будет вызываться только извне, и вам не нужна прокси-обёртка — используйте @Transactional на уровне интерфейса и включите interface-based proxy.


@Configuration
@EnableTransactionManagement(proxyTargetClass = false) // JDK proxy
public class TransactionConfig {
}



public interface UserService {
@Transactional
void createUser(User user);
}


📉 Это немного снижает overhead, особенно в высоконагруженных сервисах, где сотни тысяч вызовов @Transactional-методов.

💡 Подходит, если:
- У вас слоистая архитектура;
- Транзакции нужны только снаружи;
- Вы не используете вызовы this.someMethod() внутри сервиса.

⚠️ Не забывайте:
- JDK Proxy работает только с интерфейсами;
- Если вызываете методы внутри того же класса — прокси не сработает (и транзакция не начнётся).

📊 Профильте. Иногда замена proxyTargetClass = true на false даёт +3-5% к throughput.

👉@BookJava

Читать полностью…

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

👩‍💻 JDBC — ваш швейцарский нож для работы с данными

Приглашаем на открытый урок.

🗓 22 апреля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java Developer. Professional».

О чём поговорим:
✔️Основы JDBC: что это такое, зачем нужно и как работает
✔️Практические примеры выполнения сложных запросов
✔️Работа с транзакциями и обработка ошибок в JDBC
✔️ Оптимизация производительности при работе с данными через JDBC

Кому будет интересно:
Вебинар будет полезен разработчикам, инженерам по базам данных и архитекторам ПО, стремящимся улучшить навыки работы с базами данных и оптимизировать взаимодействие с данными.

В результате урока:
Вы научитесь эффективно использовать JDBC для работы с базами данных и сможете применять полученные знания в реальных проектах

🔗 Ссылка на регистрацию: https://vk.cc/cKRDCS

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Читать полностью…

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

❓Сталкиваетесь с задачами, когда вам нужно выбрать лучший алгоритм, но не понимаете, как анализировать их сложность? Ваш код может быть медленным или неэффективным, и вы не знаете, как это исправить?

📗На открытом вебинаре 21 апреля в 20:00 мск вы освоите важные инструменты для анализа сложности алгоритмов, улучшите свой навык решения алгоритмических задач и на примере простых алгоритмов сортировки и увидите разницу при применении алгоритмов разной степени сложности.

➡️Регистрируйтесь прямо сейчас и получите скидку на большое обучение «C# Developer» по промокоду SHARP_SPEC_4: https://vk.cc/cKRCrB

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Читать полностью…

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

🧠 Как ускорить cold start Spring Boot приложения

Как можно сократить время старта Spring Boot 3+ приложения — без GraalVM и без магии.

📌 Используем флаг:


-Dspring.context.cache.applicationContext=true


💡 Что это такое?
Это встроенный механизм кэширования ApplicationContext, появившийся в Spring Boot 3.2.

Он сохраняет результат построения контекста и позволяет повторно использовать его между запусками, особенно в тестах и development-сценариях.

⚙️ Как работает:
- При первом запуске контекст билдится как обычно.
- Затем сериализуется и сохраняется на диск.
- При следующем запуске он подгружается из кеша (если не изменился), что даёт ускорение в 2-3 раза и больше.

🚀 Отлично подходит для:
- Тестов (@SpringBootTest);
- Dev tools и локального запуска;
- Разработки больших монолитов.

⚠️ Не влияет на продакшн (там кеш не используется по умолчанию)
⚠️ Не поддерживает все конфигурации (например, динамические настройки могут инвалидировать кеш)

Простой флаг — а экономит кучу времени каждый день.

👉@BookJava

Читать полностью…

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

🧠 Частая ловушка при работе с @Transactional в Spring

Сейчас покажу вам один распространённый анти-паттерн, который легко пропустить — вызов транзакционного метода внутри того же класса.

📌 Пример:


@Service
public class UserService {

@Transactional
public void registerUser(UserDto dto) {
saveUser(dto);
}

@Transactional
public void saveUser(UserDto dto) {
// сохранение пользователя
}
}


💥 Проблема:
Spring не применит транзакцию к saveUser(), потому что вызов происходит внутри одного и того же бина — минуя прокси.

Spring AOP работает через прокси, и @Transactional "срабатывает", только если метод вызывается извне, через прокси-объект.

⚠️ Это может привести к очень странным багам: вы думаете, что транзакция есть, а её нет.

💡 Как исправить:

1. Вынести метод в отдельный бин:


@Service
public class UserSaver {
@Transactional
public void save(UserDto dto) {
// сохраняем
}
}

@Service
public class UserService {
private final UserSaver saver;

public UserService(UserSaver saver) {
this.saver = saver;
}

public void registerUser(UserDto dto) {
saver.save(dto);
}
}


2. Или использовать TransactionTemplate вручную.

✅ Всегда проверяйте, как вызываются методы с @Transactional. Особенно при рефакторинге!

👉@BookJava

Читать полностью…

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

GRASP: почему настоящая архитектура начинается не с SOLID

Хочу начать с личной предыстории. Давным‑давно, как и многие из вас, я читал умные книжки: «Чистый код» и «Чистая архитектура» Роберта Мартина, «Совершенный код» Стива Макконнелла и другие.

Также не обошли меня и классические принципы проектирования — SOLID, KISS, DRY — и, думаю, каждый читатель добавит сюда свои.

Безусловно, это всё важные и фундаментальные вещи.

Но однажды на горизонте появилось DDD — предметно‑ориентированное проектирование в изложении Эрика Эванса. Именно его «синяя книга» стала культовой и задала язык для архитектурного мышления.

Позже я открыл и «красную книгу» Вона Вернона, где DDD уже рассматривался с точки зрения практической имплементации: архитектура, код, реальные подходы в проектах.

Читая Эванса, рассматривая его диаграммы классов и примеры кода, я всё думал: как он это делает?

https://habr.com/ru/articles/900140/

👉@BookJava

Читать полностью…
Subscribe to a channel