bookjava | Unsorted

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

10986

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

Subscribe to a channel

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

Чем абстрактный класс отличается от интерфейса? В каких случаях следует использовать абстрактный класс, а в каких интерфейс?

• В Java класс может одновременно реализовать несколько интерфейсов, но наследоваться только от одного класса.
Абстрактные классы используются только тогда, когда присутствует тип отношений «is a» (является). Интерфейсы могут реализоваться классами, которые не связаны друг с другом.

• Абстрактный класс - средство, позволяющее избежать написания повторяющегося кода, инструмент для частичной реализации поведения. Интерфейс - это средство выражения семантики класса, контракт, описывающий возможности. Все методы интерфейса неявно объявляются как public abstract или (начиная с Java 8 default - методами с реализацией по-умолчанию, а поля - public static final.

• Интерфейсы позволяют создавать структуры типов без иерархии.

• Наследуясь от абстрактного, класс «растворяет» собственную индивидуальность. Реализуя интерфейс, он расширяет собственную функциональность.


Абстрактные классы содержат частичную реализацию, которая дополняется или расширяется в подклассах. При этом все подклассы схожи между собой в части реализации, унаследованной от абстрактного класса, и отличаются лишь в части собственной реализации абстрактных методов родителя. Поэтому абстрактные классы применяются в случае построения иерархии однотипных, очень похожих друг на друга классов. В этом случае наследование от абстрактного класса, реализующего поведение объекта по умолчанию может быть полезно, так как позволяет избежать написания повторяющегося кода. Во всех остальных случаях лучше использовать интерфейсы.

📲 Мы в MAX

👉@BookJava

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

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

Сегодня покажу вам интересный костыль, который до сих пор живёт в JDK и влияет на сортировку списков.

🧠 Если ты когда-нибудь пробовал сортировать LinkedList через Collections.sort(), знай — под капотом происходит скрытая магия.

📌 Collections.sort(list) сначала проверяет, какой это список. Если это RandomAccess-list (например, ArrayList) — используется быстрый сортировщик (TimSort) прямо по массиву.
⚠️ Но если это LinkedList (или любой не-рандом-доступ список), внутри происходит... преобразование списка в массив! Сначала все элементы копируются в массив, потом сортируются, а затем результат обратно заливается в твой список.


// Да, это реально работает так:
List<Integer> list = new LinkedList<>();
// ...заполняем...
Collections.sort(list);


💡 Почему так? Сортировка напрямую через LinkedList была бы очень медленной — доступ к элементам по индексу у него O(n), а не O(1) как у ArrayList. Поэтому JDK идёт на компромисс: временная потеря памяти, но ускорение времени сортировки.

⚠️ Следствие: если у тебя большой LinkedList, сортировка будет требовать двойную память: сначала весь список копируется в массив.

Совет:
Для больших коллекций, которые часто сортируются, используй ArrayList, либо готовься к затратам памяти.

📲 Мы в MAX

👉@BookJava

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

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

Что такое тернарный оператор выбора?

Тернарный условный оператор ?: - оператор, которым можно заменить некоторые конструкции операторов if-then-else.

Выражение записывается в следующей форме:

условие ? выражение1 : выражение2

Если условие выполняется, то вычисляется выражение1 и его результат становится результатом выполнения всего оператора. Если же условие равно false, то вычисляется выражение2 и его значение становится результатом работы оператора. Оба операнда выражение1 и выражение2 должны возвращать значение одинакового (или совместимого) типа.

📲 Мы в MAX

👉@BookJava

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

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

🧠 Проверяешь аргументы вручную? Используй мощь системы типов Java!

📌 Ситуация: часто в методах видишь явные проверки вроде:


public void process(User user) {
if (user == null || user.getName() == null) {
throw new IllegalArgumentException("User или его имя не могут быть null");
}
// код обработки...
}


⚠️ Это шумно и ненадежно: легко пропустить проверку или некорректно сформулировать сообщение.

💡 Современный подход (Java 17+): явно обозначь контракт метода через типы и аннотации, и пусть JVM делает проверки автоматически!

Используй стандартные средства:


import java.util.Objects;

public void process(User user) {
Objects.requireNonNull(user, "User не должен быть null");
Objects.requireNonNull(user.getName(), "Имя пользователя не должно быть null");
// код обработки...
}


или лаконично через Lombok:


import lombok.NonNull;

public void process(@NonNull User user) {
// Lombok автоматически вставит проверку на null
}


🔸 Преимущества:

* Ясность кода и контракта.
* Меньше boilerplate и человеческого фактора.
* Fail fast: сразу ловим ошибки, не откладывая.

🧠 Запомни: чем строже твоя система типов и контрактов, тем меньше неожиданностей в продакшене.

📲 Мы в MAX

👉@BookJava

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

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

📌 Обход коллекций в Java: делаем правильно!

Часто вижу, как разработчики по привычке используют старый подход с циклом for. Сегодня напомню оптимальные способы перебора коллекций в Java.

🧠 1. Foreach (Java 5+)
Коротко, ясно, подходит для большинства задач:


for (String item : collection) {
// обработка элемента
}


🧠 2. Метод forEach (Java 8+)
Отлично подходит для функционального стиля:


collection.forEach(item -> {
// обработка элемента
});


⚠️ Важно: нельзя модифицировать саму коллекцию во время такого обхода!

🧠 3. Stream API (Java 8+)
Идеален для сложной обработки с фильтрацией, маппингом и т.д.:


collection.stream()
.filter(Objects::nonNull)
.map(String::toUpperCase)
.forEach(System.out::println);


💡 Что выбрать?

* Простой перебор? Используй цикл foreach.
* Нужно быстро и функционально? collection.forEach().
* Сложные манипуляции? Только Stream API.

📌 Используйте современные подходы, это читаемость и удобство поддержки вашего кода!

📲 Мы в MAX

👉@BookJava

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

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

🧠 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

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

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

🧠 Ленивая инициализация через 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

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

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

📌 picocli — это современная библиотека для создания CLI-приложений на Java. Она упрощает разработку командных интерфейсов, обеспечивая:

* Автоматическую генерацию --help и --version
* Поддержку подкоманд (как в git commit, git push)
* Аргументы, параметры, опции с короткими и длинными флагами (-v, --verbose)
* Интеграцию с GraalVM (подходит для нативной компиляции)
* Поддержку аннотаций (аннотируй POJO — и готово!)
* Автоматическую валидацию аргументов
* Цветной вывод и гибкое форматирование
* Интерактивный режим и автодополнение

Проект активно развивается, полностью документирован и используется в сотнях продакшн-проектов. Если ты ищешь мощную и простую в использовании CLI-библиотеку на Java — picocli отличный выбор.

https://github.com/remkop/picocli

📲 Мы в MAX

👉@BookJava

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

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

🧠@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

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

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

👩‍💻 HTTP-сервер на чистой Java за 30 минут

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

🗓 21 сентября в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java разработчик. Продвинутый уровень».

Разберем, как браузер общается с сервером, и создадим работающий HTTP-сервис без Spring и сторонних библиотек.

О чем поговорим:
✔️ Как устроен HTTP-запрос
✔️ Создадим сервер на Java
✔️ Добавим несколько адресов
✔️ Откроем результат в браузере
✔️ Разберём, что скрывает Spring

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

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

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

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

📌 Java Collections

📲 Мы в MAX

👉@BookJava

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

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

💡 Чем опасен @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

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

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

🔧 Maven vs. Gradle: что выбрать разработчику?

Когда речь заходит о сборке Java-проектов, выбор обычно падает на два главных инструмента: Maven и Gradle. Оба давно стали стандартом индустрии, но каждый имеет свои особенности. Разберёмся, что выбрать 👇

☕ Maven — проверенная классика

✅ Строгая структура: легче читать и сопровождать
✅ Надёжность и предсказуемость сборки
✅ Большое комьюнити и множество плагинов
⚠️ XML-конфигурация громоздкая
⚠️ Медленнее по сравнению с Gradle

⚡ Gradle — гибкость и скорость

✅ Поддержка Kotlin и Groovy DSL
✅ Инкрементальные сборки и кэширование → быстрее
✅ Более гибкий подход к настройке
⚠️ Порог входа выше
⚠️ Иногда сложно отлаживать конфигурацию


💡 Вывод:

* 🔹 Выбирай Maven, если важны стабильность, простота и читаемость.
* 🔹 Выбирай Gradle, если хочешь максимум производительности и гибкости.

🎯 В крупных проектах Gradle становится всё популярнее, особенно при использовании Kotlin. Но в enterprise-среде Maven по-прежнему правит бал.

📲 Мы в MAX

👉@BookJava

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

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

🧠 Неочевидный 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

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

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

🧠 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

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

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

🧠 Как быстро написать компаратор в Java и не забыть про null

Часто нужно сортировать коллекции по какому-то полю. Вместо старых анонимных классов используем лямбды и статические методы из Comparator:


List<User> users = ...;

users.sort(Comparator
.comparing(User::getName, Comparator.nullsLast(String::compareToIgnoreCase))
.thenComparingInt(User::getAge)
);


📌 comparing — сравнивает по полю (например, name).
📌 nullsLast или nullsFirst — удобно обрабатывать возможные null.
📌 thenComparingInt — дополнительная сортировка (например, по возрасту).

💡 Такой подход краткий, читабельный и отлично работает с любыми полями, даже если они могут быть null.

⚠️ Никогда не забывай про null, особенно если сортируешь данные из БД или внешних источников. Ошибка NullPointerException во время сортировки может неожиданно прилететь в проде.

📲 Мы в MAX

👉@BookJava

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

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

🗄 Вебинар: JDBC: как Java-приложения взаимодействуют с базами данных
JDBC позволяет Java-приложениям работать с базами данных. Разберём подключение, SQL-запросы, транзакции и обработку ошибок.


💬 О чём поговорим
- Как подключиться к СУБД с помощью DriverManager и работать с Connection.
- Как выполнять SQL-запросы через Statement и PreparedStatement и получать результаты через ResultSet.
- Как управлять транзакциями: autocommit, commit и rollback.
- Как использовать SQLException, чтобы разобраться в причинах ошибки при выполнении запроса.

🎯 Результат урока:
- Вы разберётесь, как подключать Java-приложение к СУБД, выполнять SQL-запросы и работать с результатами.
- Узнаете, как управлять транзакциями и обрабатывать ошибки при обращении к базе данных.

👉 Для участия зарегистрируйтесь: https://vk.cc/d33JSz

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

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

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

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

🧠 10 правил безопасного Java-приложения:

1️⃣ Валидация на всех уровнях.
📌 Всегда проверяй входные данные (API, формы, запросы к БД). Используй Bean Validation (@Valid, @NotNull).

2️⃣ Используй PreparedStatement.
⚠️ Никогда не конкатенируй SQL-запросы напрямую, чтобы избежать SQL-инъекций.

3️⃣ Не раскрывай детали исключений.
📌 Отправляй клиенту общий код ошибки, а детали логируй.

4️⃣ Скрывай конфигурацию.
💡 Используй application.yml с переменными окружения для чувствительных данных (пароли, ключи API).

5️⃣ Ограничивай доступ.
📌 Spring Security — твой друг. Используй @PreAuthorize и грамотно настраивай роли и права доступа.

6️⃣ Безопасная сериализация.
⚠️ Избегай Java-стандартной сериализации. Предпочитай JSON (Jackson) с явными DTO.

7️⃣ Используй актуальные версии библиотек.
📌 Регулярно проверяй зависимости (dependency-check), чтобы избежать известных уязвимостей.

8️⃣ Грамотно логируй.
💡 Не логируй пароли, токены и персональные данные. Используй SLF4J с Logback, настрой уровень логов.

9️⃣ Безопасные куки и заголовки.
📌 Используй атрибуты куки: Secure, HttpOnly, SameSite. Spring Security поможет тебе настроить это быстро.

🔟 Настрой Security Headers.
📌 Используй заголовки:

* X-Frame-Options: DENY
* X-Content-Type-Options: nosniff
* Content-Security-Policy (CSP)

Безопасность — это не разовая задача, а процесс 💡

📲 Мы в MAX

👉@BookJava

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

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

🚀 Подборка полезных 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 лайфхак 📌
/channel/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

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

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

📌 Stream API: забудьте про peek()

Метод peek() в Java Stream API выглядит удобным для отладки, но его использование в реальном коде часто приводит к проблемам.

⚠️ Почему не стоит полагаться на peek()?

* peek() — промежуточная операция, которая не гарантирует вызов функции для каждого элемента стрима.
* Поведение зависит от терминальной операции: например, при некоторых оптимизациях JDK (особенно в параллельных стримах) вызов peek() может быть пропущен или работать непредсказуемо.

💡 Пример опасного кода:


List<String> names = Stream.of("Java", "Spring", "Hibernate")
.peek(System.out::println) // 👈 анти-паттерн!
.collect(Collectors.toList());


🧠 Лучший подход: используйте peek() исключительно для дебага, но никогда — для изменения состояния или важных операций.

✅ Правильная замена:
Если нужно выполнить действие над каждым элементом, используйте явный и безопасный подход:


List<String> names = Stream.of("Java", "Spring", "Hibernate")
.map(name -> {
log.info("Processing: {}", name); // или другая логика
return name;
})
.collect(Collectors.toList());


Или вообще вынесите логику за пределы стрима.

🧹 Держите код понятным и безопасным — забудьте про peek().

📲 Мы в MAX

👉@BookJava

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

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

Три похожих слова в 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

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

Библиотека 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

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

Библиотека 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

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

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

🧠 Трюк с @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

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

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

🧠 Как не словить 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

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

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

🧠 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

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

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

🔴 Завтра тестовое собеседование с Java-разработчиком

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

Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею

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

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

Реклама.
О рекламодателе.

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

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

🧠 Трюк с @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

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

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

🧠 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

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

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

🚀 Подборка полезных 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 лайфхак 📌
/channel/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

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