Библиотека Java разработчика
10.3K subscribers
1.05K photos
595 videos
58 files
1.43K links
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.


По всем вопросам @evgenycarter

РКН clck.ru/3KoGeP
Download Telegram
Вопросы-ответы собеседования

Можно ли создать экземпляр абстрактного класса?
Что такое интерфейс?
Как вызвать нестатический метод в статическом?
Чем отличаются параметры от аргументов в методе?
Что такое конструктор? Как его создать и вызвать?
Что такое параметризованный конструктор?
Что такое конструктор по умолчанию?
Что такое приватный конструктор? Зачем он закрытый?
Что такое статическая переменная? Как работает static поле?
Что такое статический метод? Как вызвать static метод?

источник

👉@BookJava
👍71
💡 Почему в Set.of() в Java нельзя добавить дубликаты и null?

Когда используешь Set.of(...), можно столкнуться с двумя неожиданностями:

1. Нельзя добавлять дубликаты
2. Нельзя добавлять null

Разбираемся, почему так:

🔐 Set.of(...) — это immutable Set

Метод Set.of(...), добавленный в Java 9, создаёт неизменяемое множество. Это значит:

* После создания ты не можешь изменить его (добавить, удалить элемент).
* Все элементы внутри должны быть уникальны и не должны быть null.

📛 Почему нельзя дубликаты?

Потому что Set по определению — это коллекция уникальных элементов.
А Set.of(...) бросает IllegalArgumentException, сразу во время создания, если переданы дубликаты:


Set.of("a", "b", "a"); // 💥 Бросит исключение!


Это сделано для того, чтобы не было тихих ошибок — чтобы ты сразу увидел, что передал неуникальные значения.

🕳️ Почему нельзя null?

Set.of(...) не принимает null, потому что он реализован через внутренние immutable структуры, которые не допускают null`-значений. При попытке добавить `null получишь NullPointerException.


Set.of("a", null); // 💥 NullPointerException


Это сделано сознательно — null может вести к неочевидным багам и плохо сочетается с концепцией неизменяемых коллекций.


👀 Хочешь изменяемый Set, который принимает null и дубликаты фильтрует сам? Используй HashSet:


Set<String> set = new HashSet<>();
set.add(null); // Можно


👉@BookJava
👍4🤔3
🧠 Трюк с @EventListener в Spring Boot — неочевидная ловушка

Когда ты используешь @EventListener для обработки событий в Spring, ты можешь попасть в баг, который очень сложно отловить в бою — пропущенные события.

📌 Пример:


@Component
public class MyListener {

@EventListener
public void on(MyEvent event) {
// логика
}
}


Если MyListener бин ещё не проинициализирован, а событие уже публикуется (ApplicationEventPublisher#publishEvent), то метод on просто не будет вызван. Spring не будет "накапливать" события для будущих слушателей.

⚠️ Это особенно критично, если ты триггеришь событие в @PostConstruct или в CommandLineRunner, а слушатель находится в другом бине, который ещё не загружен.

💡 Как избежать:

1. Используй явное управление порядком инициализации через @DependsOn.
2. Не публикуй события слишком рано — лучше в ApplicationReadyEvent:


@Component
public class Publisher {

private final ApplicationEventPublisher publisher;

public Publisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}

@EventListener(ApplicationReadyEvent.class)
public void onReady() {
publisher.publishEvent(new MyEvent(this));
}
}


🧵 Альтернатива: если тебе нужно гарантированное выполнение в момент старта — лучше использовать ApplicationRunner или InitializingBean, где порядок можно контролировать проще.

👉@BookJava
👍7
Совет 💡

Если вы хотите получить сообщение о первопричине, вы можете легко и безопасно получить его с помощью Apache Commons ExceptionUtils. Методы getRootCauseMessage(Exception ex) выдают сообщение в виде {ClassNameWithoutPackage} {ThrowableMessage}

👉@BookJava
👍7💩1
🧠 Spring Boot + MapStruct: как избежать null при обновлении сущности

При обновлении сущностей через MapStruct бывает типичная проблема: маппер затирает уже существующие поля null'ами, если они не переданы во входном DTO. Это может легко привести к потере данных. Покажу, как решить это изящно.

Допустим, у нас есть:


public class UserDto {
private String name;
private String email;
}


И сущность:


@Entity
public class User {
private String name;
private String email;
}


Если ты используешь обычный @MappingTarget, то:


@MappingTarget User user, UserDto dto


— не переданное поле email в dto затирает значение в user.

📌 Чтобы этого не происходило, добавь в маппер:


@Mapper(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
public interface UserMapper {
void update(@MappingTarget User user, UserDto dto);
}


💡 NullValuePropertyMappingStrategy.IGNORE говорит MapStruct: не трогай те поля, которые в DTO пришли как null.

⚠️ Это работает только для объектов, не для Optional и не для примитивов. Там потребуется другая стратегия — например, обёртки или @Condition.

Такой подход позволяет обновлять только те поля, которые реально пришли, и не бояться случайного затирания.

👉@BookJava
👍64
Media is too big
VIEW IN TELEGRAM
Создание REST API с использованием Spring WebFlux и Security

00:00:00 Введение
00:00:20 Создание проекта
00:11:36 Создание миграций БД
00:15:40 Создание базовых классов
00:23:20 Реализация логики генерации JWT токена
00:46:30 Реализация логики валидации JWT токена
00:53:05 Построения цепочки аутентификации
01:04:22 Финальная конфигурация с использованием SecurityWebFilterChain
01:12:11 Реализация REST контроллеров
01:23:15 Проверка REST API средствами Postman
01:24:21 Добавление и конфигурация обработчика ошибок
01:25:40 Заключение

Ссылка на Github репозиторий https://github.com/proselytear/webfluxsecurity

источник

👉@BookJava
👍7🔥1
💡 Совет Java

Заменяем и переворачиваем последнее слово в строке — без использования StringBuilder!

Когда-нибудь задумывался, как в Java перевернуть только последнее слово в предложении и вставить его обратно? 🤔

Вот лаконичное решение на чистом Java, без использования StringBuilder.

💡 Отлично подойдёт новичкам, чтобы лучше понять:

1. Логику реверса строки 🔁
2. Работу с массивами и циклами 🧩
3. Почему важно избегать изменяемых классов, вроде StringBuilder, когда тренируешь основы 💪

👉@BookJava
👎8👍1💩1
🚀 7 самых полезных методов Stream API в Java 21

Работаешь с коллекциями в Java? Тогда Stream API — твой лучший друг. В Java 21 он стал ещё удобнее. Вот краткая шпаргалка по самым нужным методам — с понятными примерами 👇


🔹 1. filter(Predicate)
📌 Фильтрует элементы по условию.
🧠 Пример: оставить только чётные числа:


List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.toList();



🔹 2. map(Function)
📌 Преобразует каждый элемент.
🧠 Пример: сделать все имена заглавными:


List<String> upperCaseNames = names.stream()
.map(String::toUpperCase)
.toList();



🔹 3. flatMap(Function)
📌 «Сплющивает» вложенные коллекции.
🧠 Пример: объединить вложенные списки:


List<String> words = nestedLists.stream()
.flatMap(List::stream)
.toList();



🔹 4. collect(Collector)
📌 Собирает элементы в коллекцию.
🧠 Пример: получить Set из списка:


Set<String> uniqueNames = names.stream()
.collect(Collectors.toSet());



🔹 5. forEach(Consumer)
📌 Выполняет действие для каждого элемента.
🧠 Пример: распечатать все имена:


names.stream().forEach(System.out::println);



🔹 6. reduce(BinaryOperator)
📌 Сводит все элементы к одному значению.
🧠 Пример: сумма чисел:


int sum = numbers.stream()
.reduce(0, Integer::sum);



🔹 7. takeWhile / dropWhile (Java 9+)
📌 Берёт или пропускает элементы, пока выполняется условие.
🧠 Пример: взять только числа < 10:


List<Integer> lessThanTen = numbers.stream()
.takeWhile(n -> n < 10)
.toList();



💡 Лайфхак: вместо collect(...) используй toList() и toSet() — код станет чище, а производительность выше.

👇 А ты какие методы используешь чаще всего? Поделись в комментах — реальный опыт всегда круче теории!

👉@BookJava
👍3👎3💩3
Проверка на null с помощью Optional

Optional помогает избежать NullPointerExceptions.


String name = "Alice";
Optional<String> maybeName = Optional.ofNullable(name);
System.out.println(maybeName.orElse("Nobody")); // Output: Alice


👉@BookJava
🤡6👍51
🔍 Enumeration vs Iterator в Java

Java-программисты часто сталкиваются с двумя интерфейсами для перебора коллекций: устаревшим Enumeration и современным Iterator. Разберём ключевые отличия:

1️⃣ Происхождение

* Enumeration появился в Java 1.0 и используется в старых классах (Vector, Hashtable).
* Iterator введён в Java 1.2 вместе с коллекциями из пакета java.util (List, Set и т.д.).

2️⃣ Методы и возможности

* Enumeration предоставляет методы hasMoreElements() для проверки и nextElement() для получения следующего элемента, но не умеет удалять элементы во время итерации.
* Iterator использует hasNext() и next(), а также имеет метод remove() для безопасного удаления элементов прямо во время обхода.

3️⃣ Fail-fast поведение

* Iterator отслеживает изменения коллекции извне и при обнаружении бросает ConcurrentModificationException.
* Enumeration такого механизма не имеет — внешние модификации могут приводить к непредсказуемым результатам.

4️⃣ Поддержка дженериков

* Enumeration не типобезопасен (до Java 1.5), что требовало кастов.
* Iterator<E> полностью интегрирован с дженериками, что позволяет избежать ClassCastException.

5️⃣ Когда использовать

* Iterator — выбор по умолчанию для всех современных коллекций: гибкость, безопасность и поддержка удаления.
* Enumeration — только при взаимодействии с legacy-API (Vector, Hashtable и др.).

💡 Вывод: выбирайте Iterator — он более универсален, безопасен и дружелюбен к дженерикам. Enumeration сохранён в языке лишь ради обратной совместимости.

👉@BookJava
6👍1
🧠 Быстрый способ найти performance-проблемы в Spring Boot-приложении

Сейчас покажу, как быстро узнать, какие бины подгружаются дольше всего при старте Spring Boot-приложения.

📌 Добавь в application.yml:


spring:
application:
name: demo
main:
log-startup-info: true
boot:
startup:
logging:
enabled: true


🔥 Теперь при старте приложения Spring Boot 3+ покажет top-N самых "тяжёлых" бинов:


Startup completed in 3.567 seconds
Application started in 3.789 seconds (JVM running for 4.112)
Bean instantiation and initialization:
145 ms -> com.example.HeavyBean
95 ms -> com.example.AnotherBean


💡 Это встроенный инструмент, который раньше был только в Spring Boot Actuator!

📈 Отлично помогает:

при оптимизации старта,
для понимания сложностей DI,
при миграции на новые версии.

⚠️ Подходит только для Spring Boot 2.4+ .

👉@BookJava
👍61
Media is too big
VIEW IN TELEGRAM
Kafka Cluster в Docker

Настроим docker-compose.yml для кафка кластера и запустим наше приложение с кафкой из докера

00:00 Intro
00:30 Конфигурация одного сервера
10:23 Запуск и проверка работы
15:15 Конфигурация кластера
18:05 Запуск кластера и проверка работы
19:30 environment.env
21:30 environment.env
22:56 Итог

источник

👉@BookJava
3👍2
Media is too big
VIEW IN TELEGRAM
Java. Представление отрицательных чисел. Преобразование цветной фотографии в черно-белую.

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

👉@BookJava
👍31
📌Примеры базовых алгоритмов


➡️ 1. Сортировка пузырьком (Bubble Sort)


public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// обмен
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}



➡️ 2. Бинарный поиск (Binary Search)


public class BinarySearch {
public static int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;

while (left <= right) {
int mid = (left + right) / 2;

if (arr[mid] == target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}

return -1; // элемент не найден
}
}


➡️ 3. Поиск максимального элемента в массиве


public class MaxInArray {
public static int findMax(int[] arr) {
int max = arr[0];
for (int num : arr) {
if (num > max) max = num;
}
return max;
}
}


➡️ 4. Факториал через рекурсию


public class Factorial {
public static long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
}


➡️ 5. Проверка, является ли строка палиндромом


public class PalindromeCheck {
public static boolean isPalindrome(String str) {
int left = 0, right = str.length() - 1;

while (left < right) {
if (str.charAt(left++) != str.charAt(right--)) {
return false;
}
}

return true;
}
}


👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍71
This media is not supported in your browser
VIEW IN TELEGRAM
Как скомпилировать исходники java вручную

В повседневной работе никто из нас не компилирует исходники Java вручную. За нас это делают такие инструменты как maven, gradle или интегрированная среда разработки типа Idea.

Но для понимания процессов, которые происходят при каждом тестовом запуске вашего приложения, имеет смысл хотя бы один попробовать это сделать самостоятельно прямо из консоли.

https://devmark.ru/article/manual-java-compiling

👉@BookJava
👍6
Как обобрать дерево в несколько потоков?

Всем привет, меня зовут Антон, я Java‑разработчик в Сбере, подразделение SberWorks. Я разрабатываю Giga IDE — новую IDE на основе IntelliJ IDEA. В ходе работы столкнулся с тем, что при открытии проектов происходит сканирование всех папок для поиска тех или иных файлов. Если обобщить, то задача сводится к обходу дерева. Я решил подробнее рассмотреть эту тему, причём с прицелом на многопоточность.

Задача обхода деревьев далеко не нова, существуют два основных подхода: обход в ширину и глубину. В первом случае удобно применять рекурсивный алгоритм, а во втором — понадобится дополнительная коллекция, в которую будут складываться узлы дерева, но всё это в один поток, а я решил рассмотреть эту задачу в многопоточной интерпретации.

https://habr.com/ru/companies/sberbank/articles/921528/

👉@BookJava
👍6🤔1
Вопрос с собеседования: Опишите жизненный цикл Spring Bean

Beans – центральный объект заботы Spring Framework. За кулисами фреймворка с ними происходит множество процессов. Во многие из них можно вмешаться, добавив собственную логику в разные этапы жизненного цикла. Через следующие этапы проходит каждый отдельно взятый бин:

1. Инстанцирование объекта. Техническое начало жизни бина, работа конструктора его класса;

2. Установка свойств из конфигурации бина, внедрение зависимостей;

3. Нотификация aware-интерфейсов. BeanNameAware, BeanFactoryAware и другие. Мы уже писали о таких интерфейсах ранее. Технически, выполняется системными подтипами BeanPostProcessor, и совпадает с шагом 4;

4. Пре-инициализация – метод postProcessBeforeInitialization() интерфейса BeanPostProcessor;

5. Инициализация. Разные способы применяются в таком порядке:
• Метод бина с аннотацией @PostConstruct из стандарта JSR-250 (рекомендуемый способ);
• Метод afterPropertiesSet() бина под интерфейсом InitializingBean;
• Init-метод. Для отдельного бина его имя устанавливается в параметре определения initMethod. В xml-конфигурации можно установить для всех бинов сразу, с помощью default-init-method;

6. Пост-инициализация – метод postProcessAfterInitialization() интерфейса BeanPostProcessor.
Когда IoC-контейнер завершает свою работу, мы можем кастомизировать этап штатного уничтожения бина. Как со всеми способами финализации в Java, при жестком выключении (kill -9) гарантии вызова этого этапа нет. Три альтернативных способа «деинициализации» вызываются в том же порядке, что симметричные им методы инициализации:

1. Метод с аннотацией @PreDestroy;
2. Метод с именем, которое указано в свойстве destroyMethod определния бина (или в глобальном default-destroy-method);
3. Метод destroy() интерфейса DisposableBean.

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

👉@BookJava
👍9🔥32
🚀 Java Streams: Основные методы для чистого и эффективного кода!

Java Streams предлагают множество методов для упрощения манипуляций с данными и повышения читаемости кода.
Вот краткое руководство с примерами:

Освойте эти методы, чтобы писать более чистый и эффективный код на Java! 💡

👉@BookJava
👍5
JEP 511 расширяет язык программирования Java, добавляя возможность кратко импортировать все пакеты, экспортируемые модулем — это упрощает повторное использование модульных библиотек, но при этом не требует, чтобы код, осуществляющий импорт, сам находился в модуле.

➡️Подробнее: https://openjdk.org/jeps/511

👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
Media is too big
VIEW IN TELEGRAM
Что такое Java?

Разбираем собеседование по Java-кодингу.

👉@BookJava
👍7