bookjava | Unsorted

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

10986

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

Subscribe to a channel

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

🎁 Optional: Лекарство от NullPointerException

Тони Хоар назвал изобретение null своей "ошибкой на миллиард долларов". NullPointerException (NPE) - самый частый кошмар Java-разработчика.
В Java 8 появился Optional<T> - класс-обертка, который явно говорит: "Здесь значения может и не быть".

📦 Что внутри?

Представьте Optional как коробку.

🔴В ней может лежать объект (Non-empty).
🔴Или она может быть пустой (Empty).

Главное правило: Никогда не возвращайте null из метода, если можно вернуть Optional.empty().

🚫 Как делать НЕ надо

Самая частая ошибка новичка, использовать Optional как старый добрый if (x != null):


Optional<User> userOpt = findUser("Alex");

// ❌ ПЛОХО: Это тот же null-check, только сложнее
if (userOpt.isPresent()) {
System.out.println(userOpt.get().getName());
}



Метод .get() - это зло. Если коробка пуста, он бросит NoSuchElementException, и вы просто поменяли шило (NPE) на мыло.

✅ Как делать НАДО (Functional Style)

Вся мощь Optional раскрывается, когда вы строите цепочки вызовов, как в стримах.

1. Если значение есть, сделай что-то (ifPresent)


findUser("Alex").ifPresent(user -> System.out.println(user.getName()));



2. Если значения нет, верни дефолт (orElse)


// Вернет юзера или создаст нового "Guest", если не нашел
User user = findUser("Alex").orElse(new User("Guest"));



3. Если значения нет — брось ошибку (orElseThrow)


User user = findUser("Alex")
.orElseThrow(() -> new IllegalArgumentException("User not found"));



4. Преобразование внутри коробки (map)
Допустим, нам нужен не сам юзер, а его email. Если юзера нет, то и email нет.


String email = findUser("Alex")
.map(User::getEmail) // Достаем email (если юзер есть)
.map(String::toUpperCase) // В верхний регистр (если email был)
.orElse("UNKNOWN"); // Если хоть на одном этапе было пусто



⚡ Золотые правила использования

1. Только для возвращаемых значений! Не используйте Optional как тип поля в классе или аргумент метода. Это лишний оверхед и мусор в коде.
2. orElse() vs orElseGet():
🔴orElse(new Object()) - объект создается всегда, даже если он не нужен.
🔴orElseGet(() -> new Object()) - объект создается только если в коробке пусто (лениво). Используйте этот вариант для тяжелых объектов.


🔥 Итог

Optional спасает не тем, что убирает null, а тем, что заставляет вас явно обработать случай отсутствия значения.
Забудьте про .get(). Используйте .map(), .filter() и .orElse().

#Java #Optional #CleanCode #NoMoreNPE

📲 Мы в MAX

👉@BookJava

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

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

🛒 Collectors: Собираем урожай Stream API

Мы отфильтровали, преобразовали и отсортировали данные. Теперь их нужно сложить в коробочку, чтобы использовать дальше. Для этого существует терминальная операция .collect().

Внутрь нее мы передаем специальный объект - Collector. Чтобы не писать его вручную, в Java есть утилитный класс Collectors с готовыми решениями на все случаи жизни.

📦 Базовый набор (Must Have)

1. В список или множество
💙Collectors.toList() - собирает все в ArrayList (но тип не гарантирован).
💙Collectors.toSet() - собирает в HashSet (убирает дубликаты).
💙Java 16+ Update: Теперь можно просто писать .toList() прямо у стрима, без collect(...). Это создает неизменяемый список.


2. В строку (joining)
💙Больше не нужно мучиться с StringBuilder в циклах.
💙Collectors.joining(", ") - склеит строки через запятую.



🔑 Продвинутый уровень: Карты и Группировки

Самая мощная магия происходит здесь.

3. В Map (toMap)
Превращает список объектов в Map (ключ-значение).
💙Синтаксис: toMap(Function keyMapper, Function valueMapper)
💙Важно: Если ключи совпадут, вылетит IllegalStateException.
💙Лечение: Третий аргумент - "мердж-функция" (что делать при конфликте).


4. Группировка (groupingBy)
Аналог GROUP BY из SQL. Это киллер-фича Stream API.
💙Разделяет элементы на группы по какому-то признаку и кладет их в Map<Критерий, Список>.


💻 Примеры в коде

Представьте, у нас есть класс User(String name, String role).


List<User> users = List.of(
new User("Alex", "ADMIN"),
new User("Bob", "USER"),
new User("Charlie", "USER")
);

// 1. Склеиваем имена в одну строку
String names = users.stream()
.map(User::getName)
.collect(Collectors.joining(", "));
// Результат: "Alex, Bob, Charlie"

// 2. Превращаем в Map: Имя -> Роль
Map<String, String> userMap = users.stream()
.collect(Collectors.toMap(
User::getName, // Ключ
User::getRole // Значение
));
// Результат: {Alex=ADMIN, Bob=USER, Charlie=USER}

// 3. Группируем по Роли (SQL GROUP BY)
Map<String, List<User>> byRole = users.stream()
.collect(Collectors.groupingBy(User::getRole));
// Результат:
// {
// "ADMIN": [User(Alex)],
// "USER": [User(Bob), User(Charlie)]
// }



⚡ Полезный лайфхак

В groupingBy можно передать второй коллектор! Например, чтобы не просто сгруппировать пользователей, а сразу посчитать их количество в каждой группе:


Map<String, Long> countByRole = users.stream()
.collect(Collectors.groupingBy(
User::getRole,
Collectors.counting() // Downstream collector
));
// Результат: {ADMIN=1, USER=2}



🔥 Итог

Collectors позволяют превратить поток данных в любую удобную структуру: от простого списка до сложной многоуровневой мапы.

#Java #StreamAPI #Collectors #JavaTips

📲 Мы в MAX

👉@BookJava

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

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

🗺 map() vs flatMap(): Битва трансформеров

Оба метода находятся в конвейере (Intermediate operations) и нужны для преобразования данных. Но работают они с разной геометрией.

1️⃣ map() - Один к одному (1:1)

Самый простой случай. Вы берете элемент, делаете с ним что-то и возвращаете один измененный элемент. Структура потока не меняется.

💙Логика:
💙Пример: Есть список сотрудников (Employee), нужно получить список их имен (String).
💙Аналогия: У вас есть коробка с яблоками. Вы берете каждое яблоко, чистите его и кладете обратно. В итоге у вас столько же объектов, просто они изменились.


stream.map(employee -> employee.getName()) // Был Employee, стал String



2️⃣ flatMap() - Один ко многим (1:N) + Сплющивание

Этот метод нужен, когда элементы стрима - это контейнеры (списки, массивы), и вам нужно достать содержимое наружу, "сплющив" всё в один поток.

💙Логика:
💙Пример: Есть список отделов (Department), в каждом отделе - список сотрудников (List<Employee>). Вы хотите получить один общий список всех сотрудников компании.
💙Аналогия: У вас есть коробка, внутри которой лежат маленькие коробочки с конфетами.
💙Если сделать map, у вас будет поток коробочек.
💙Если сделать flatMap, вы высыпаете конфеты из всех коробочек в одну большую кучу.



💻 Код: Почувствуйте разницу

Допустим, у нас есть "Списков списков":
List<List<String>> nestedList = List.of(List.of("A", "B"), List.of("C", "D"));

❌ Попытка с map:


// Мы получим Stream из Списков: Stream<List<String>>
nestedList.stream()
.map(list -> list.stream())
.toList();
// Результат: [[A, B], [C, D]] — Матрёшка осталась!



✅ Решение с flatMap:


// Мы получим единый Stream строк: Stream<String>
nestedList.stream()
.flatMap(list -> list.stream()) // Превращаем каждый список в стрим и сливаем
.toList();
// Результат: [A, B, C, D] — То, что нужно!



⚡ Когда что использовать?

1. map: Используем в 90% случаев. Когда нужно просто превратить А в Б (Число в Строку, Объект в Поле объекта).
2. flatMap: Используем, когда нужно убрать вложенность.
💙List<List<T>> List<T>
💙Работа с файлами (список строк из списка файлов).
💙Работа с Order List<LineItem>.


🔥 Итог

💙 map преобразует элементы.
💙flatMap преобразует и разворачивает структуру.

#Java #StreamAPI #MapVsFlatMap #InterviewQuestions

📲 Мы в MAX

👉@BookJava

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

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

Вопросы-ответы собеседования

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

источник

📲 Мы в MAX

👉@BookJava

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

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

🍒 Магия двойного двоеточия: Method References

Мы уже научились писать лямбды. Но иногда даже лямбда кажется слишком громоздкой. Если ваша лямбда не делает ничего, кроме вызова одного уже существующего метода, Java позволяет использовать Method Reference (ссылку на метод).

Синтаксис простой: Класс::метод (без скобок!).

🛠 4 ситуации, когда это работает

Есть 4 основных способа использовать оператор ::. Важно понимать разницу, чтобы не путаться.

1. Ссылка на статический метод
💙 Лямбда: s -> Integer.parseInt(s)
💙 Reference: Integer::parseInt
💙 Суть: Просто перенаправляем входящий параметр в статический метод.


2. Ссылка на метод конкретного объекта
💙 Лямбда: obj -> System.out.println(obj)
💙 Reference: System.out::println
💙 Суть: У нас уже есть готовый объект (System.out), и мы вызываем его метод для каждого элемента.


3. Ссылка на метод произвольного объекта определенного типа (Самый хитрый пункт! 🤯)
💙 Лямбда: s -> s.toLowerCase()
💙 Reference: String::toLowerCase
💙 Суть: Здесь метод вызывается у самого объекта, который пришел в лямбду. Хотя синтаксис похож на статический вызов, это вызов инстанс-метода.


4. Ссылка на конструктор
💙 Лямбда: () -> new ArrayList<>()
💙 Reference: ArrayList::new
💙 Суть: Используется для создания новых объектов (часто в Stream API: Collectors.toCollection(ArrayList::new)).


💻 Пример: Было vs Стало

Смотрите, как очищается код. Допустим, у нас есть список имен:


List<String> names = Arrays.asList("Alex", "Bob", "Anna");

// ❌ Уровень 1: Анонимный класс (Олдскул)
names.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});

// ⚠️ Уровень 2: Обычная лямбда
names.forEach(s -> System.out.println(s));

// ✅ Уровень 3: Method Reference (Красота)
names.forEach(System.out::println);



🧠 Как понять, когда использовать?

Если ваша лямбда выглядит так:
x -> Class.method(x)
или
x -> x.method()
...смело меняйте её на ::.

Но! Если вам нужно изменить аргумент перед передачей (например, x -> System.out.println("Name: " + x)), то Method Reference уже не подойдет, оставайтесь на лямбде.

#Java #CleanCode #MethodReference

📲 Мы в MAX

👉@BookJava

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

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

☕ Функциональные интерфейсы: Магия за кулисами Лямбд

Если вы используете лямбды (а вы наверняка их используете), значит, вы работаете с функциональными интерфейсами. Давайте разберем, что это такое, зачем нужна аннотация и какие интерфейсы вы обязаны знать наизусть.

🎯 Что это такое?

Функциональный интерфейс - это интерфейс, который содержит ровно один абстрактный метод.

Именно это ограничение позволяет компилятору превращать лямбда-выражение в экземпляр этого интерфейса.

💙 Примечание: В интерфейсе может быть сколько угодно default или static методов. Главное - только один абстрактный.

📝 Аннотация @FunctionalInterface

Ставить её над интерфейсом не обязательно, но хорошим тоном считается ставить.
Зачем? Она работает как защита от дурака: если вы или ваш коллега случайно добавите второй абстрактный метод в интерфейс, компилятор сразу выдаст ошибку, не дожидаясь падения кода в местах использования лямбд.



🧰 Шпаргалка: "Великолепная четверка"

В пакете java.util.function уже есть готовые интерфейсы на 99% случаев жизни. Не пишите свои велосипеды, пока не выучите эти:

1. Predicate <T>
💙Что делает: Проверяет условие.
💙 Метод: boolean test(T t)
💙 Где нужен: Фильтрация стримов (`filter`), проверки.


2. Consumer <T>
💙 Что делает: "Потребляет" объект, ничего не возвращая.
💙 Метод: void accept(T t)
💙 Где нужен: Вывод на экран, запись в БД, forEach.


3. Supplier <T>
💙 Что делает: "Поставляет" объект (из ниоткуда), ничего не принимая.
💙 Метод: T get()
💙 Где нужен: Ленивая инициализация, генерация значений, orElseGet.


4. Function <T, R>
💙 Что делает: Превращает объект типа T в объект типа R.
💙 Метод: R apply(T t)
💙 Где нужен: Преобразование данных, map в стримах.


💻 Пример в коде


@FunctionalInterface
interface Converter {
int stringToInt(String s);
}

public class Main {
public static void main(String[] args) {
// 1. Создаем реализацию через лямбду
Converter converter = str -> Integer.parseInt(str);

// 2. Использование стандартного Consumer
java.util.function.Consumer<Integer> print = x -> System.out.println("Result: " + x);

int result = converter.stringToInt("123");
print.accept(result); // Вывод: Result: 123
}
}



🔥 Итог

Функциональные интерфейсы - это контракт для лямбда-выражений. Используйте стандартные из java.util.function, чтобы ваш код был понятен другим разработчикам без лишних документаций.

#Java #Core #Lambda #FunctionalProgramming

📲 Мы в MAX

👉@BookJava

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

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

🧵 String.join(): Склеиваем строки без боли

Помните те времена, когда для объединения списка строк через запятую приходилось писать циклы, использовать StringBuilder, а потом еще и аккуратно удалять последний разделитель? 🤯

Начиная с Java 8, у нас есть элегантный статический метод String.join, который делает код чистым и читаемым.

🛠 Как это работает?

Метод принимает разделитель (delimiter) и элементы, которые нужно склеить. Элементами могут быть как просто перечисление строк (varargs), так и любая коллекция (Iterable).

1️⃣ Пример с перечислением строк:


String result = String.join(" -> ", "Wake up", "Code", "Sleep");

System.out.println(result);
// Вывод: Wake up -> Code -> Sleep


2️⃣ Пример с коллекцией (List, Set):


List<String> langs = Arrays.asList("Java", "Kotlin", "Groovy");

// Больше никаких циклов!
String output = String.join(" | ", langs);

System.out.println(output);
// Вывод: Java | Kotlin | Groovy


🧐 Важные нюансы:

- Null-safe (частично): Если сам список или массив равен null, вы получите NullPointerException. Но если null является одним из элементов списка, метод просто преобразует его в строку "null".
- Под капотом: Метод использует StringJoiner (еще один класс из Java 8), что обеспечивает неплохую производительность по сравнению с обычной конкатенацией через +.

🚀 Когда использовать?

Используйте String.join, когда у вас уже есть коллекция или массив строк, и вам нужно быстро собрать их в одну строку.

Если же вы работаете со Stream API, то лучше подойдет коллектор:
.collect(Collectors.joining(", "))


#Java #Core #Tips #CleanCode

📲 Мы в MAX

👉@BookJava

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

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

Совет Spring Framework💡

Вы можете инжектировать (autowire) бины, которые могут отсутствовать, обернув их в java.util.Optional. Таким образом вы сообщаете, что этот бин является необязательным, избегаете исключения, если он не существует, и можете аккуратно обработать его отсутствие с помощью Optional API.

📲 Мы в MAX

👉@BookJava

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

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

☕️ Spring Core: Зачем нужна аннотация @Bean?

Если вы работаете со Spring, вы видите эту аннотацию постоянно. Но чем она отличается от простого навешивания @Component над классом? Давайте разберем.

💡 Что это такое?

Аннотация @Bean используется в методах конфигурационных классов (помеченных @Configuration). Она говорит Spring-контейнеру:

"Эй, Spring! Выполни этот метод, возьми то, что он вернет, и сохрани этот объект у себя в контексте (ApplicationContext). Управляй им как бином".


🛠 Как это выглядит?


@Configuration
public class AppConfig {

// Мы явно создаем объект и отдаем его Спрингу
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper(); // Например, библиотека Jackson
}
}




🔥 Когда использовать @Bean, а когда @Component?

Это самый частый вопрос на собеседованиях.

1. Используйте @Component@Service, @Repository), когда:

- Это ваш класс. Вы имеете доступ к исходному коду.
- Вам нужна магия автоматического сканирования (component scanning). Вы просто ставите аннотацию над классом, и Spring сам его находит.

2. Используйте @Bean, когда:

- Сторонние библиотеки. Вы не можете зайти в класс ObjectMapper (из Jackson) или AmazonS3Client и написать там @Component, потому что это чужой код (read-only). Чтобы добавить такой объект в контекст Spring, вы создаете для него метод с @Bean.
- Сложная логика создания. Если создание объекта требует условий (if/else) или сложной конфигурации, проще описать это в методе явно.

⚙️ Фишки @Bean

- Имена: По умолчанию имя бина совпадает с именем метода. Можно изменить: @Bean("myCoolBean").
- Init/Destroy: Можно указать методы, которые сработают при создании или удалении бина: @Bean(initMethod = "init", destroyMethod = "cleanup").
- Зависимости: Если методу с @Bean нужны аргументы, Spring автоматически найдет и подставит их из контекста.

Итог: @Component - для автоматизации своих классов, @Bean - для ручного контроля и чужих библиотек.


#Java #Spring #SpringBoot #Coding #Education

📲 Мы в MAX

👉@BookJava

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

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

Совет SpringBoot

Вы можете запустить метод в Spring @Service сразу после запуска приложения, аннотируя его с помощью
@EventListener (ApplicationReadyEvent.class). Метод не может иметь параметров. Иногда я неправильно использую его, чтобы быстро протестировать определенный метод Spring Service.

📲 Мы в MAX

👉@BookJava

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

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

⚡️ Микро-оптимизация: Прощай, AtomicInteger, привет, VarHandle!

👋 Сегодня поговорим о том, как можно немного ускорить ваш код, работающий с атомарными операциями, и сделать его более "современным" с помощью VarHandle, который появился в Java 9.

🧐 Проблема с AtomicInteger

AtomicInteger - это классический способ обеспечить атомарные операции (например, инкремент) над целым числом без блокировок, используя механизм Compare-And-Swap (CAS).

Однако, у него есть небольшой недостаток: он добавляет слой косвенности. Методы типа getAndIncrement() в AtomicInteger обычно вызывают внутренние статические методы из класса sun.misc.Unsafe (или его аналогов в более новых версиях), передавая в них ссылку на объект, смещение поля и новое значение.


// Примерно так это выглядит внутри AtomicInteger
// В реальном коде это, конечно, оптимизировано, но суть та же.
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}


✨ Встречайте VarHandle!

VarHandle - это новый, более гибкий и, что самое главное, более производительный низкоуровневый API для работы с полями переменных (как экземпляров, так и статических) с заданными барьерами памяти и атомарностью.

Главное преимущество? JIT-компилятор (C2) лучше оптимизирует доступ через VarHandle, чем через старые обертки типа AtomicInteger или прямые вызовы Unsafe.

🛠 Как использовать VarHandle вместо AtomicInteger

Вместо того, чтобы хранить значение в отдельном объекте AtomicInteger, мы просто объявляем поле volatile в нашем классе и получаем VarHandle для этого поля.

1. Объявляем поле:


public class Counter {
private volatile int count = 0; // Поле должно быть volatile
// ...
}


2. Создаем VarHandle:

VarHandle нужно инициализировать один раз (обычно в статическом блоке) для доступа к полю.


private static final VarHandle COUNT_HANDLE;

static {
try {
// Получаем VarHandle для поля 'count' класса 'Counter' с типом int
COUNT_HANDLE = MethodHandles.lookup().findVarHandle(
Counter.class,
"count",
int.class
);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
}
}


3. Выполняем атомарную операцию:

Метод getAndAdd VarHandle работает точно так же, как getAndAdd в AtomicInteger.


public int increment() {
// В отличие от AtomicInteger, где первый аргумент неявен,
// VarHandle требует первым аргументом *объект*,
// к полю которого мы обращаемся.
return (int) COUNT_HANDLE.getAndAdd(this, 1);
}


🚀 Результат микро-оптимизации

В бенчмарках (например, с использованием JMH) можно увидеть, что операции getAndAdd() через VarHandle могут быть незначительно быстрее (зачастую на 5-10%), чем те же операции через AtomicInteger, особенно под высокой нагрузкой, благодаря более эффективной генерации кода JIT-компилятором.

🛑 Важно: Это микро-оптимизация. В большинстве приложений вы не заметите разницы. Но если вы пишете критически важные фреймворки, высоконагруженные коллекции или библиотеки, где каждая наносекунда на счету, переход на VarHandle может быть оправдан.



VarHandle - это не только способ микро-оптимизации, но и стандартный, гибкий API для атомарного доступа, который заменил устаревший и менее безопасный Unsafe. Для нового кода, где требуется низкоуровневый атомарный доступ, стоит отдавать предпочтение именно ему.

📲 Мы в MAX

👉@BookJava

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

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

Что такое «ссылка на метод»?

Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом method reference (ссылка на метод) для непосредственной передачи этого метода. Такая ссылка передается в виде:

⚫️имя_класса::имя_статического_метода для статического метода;
⚫️объект_класса::имя_метода для метода экземпляра;
⚫️название_класса::new для конструктора.
Результат будет в точности таким же, как в случае определения лямбда-выражения, которое вызывает этот метод.


private interface Measurable {
public int length(String string);
}

public static void main(String[] args) {
Measurable a = String::length;
System.out.println(a.length("abc"));
}


Ссылки на методы потенциально более эффективны, чем использование лямбда-выражений. Кроме того, они предоставляют компилятору более качественную информацию о типе и при возможности выбора между использованием ссылки на существующий метод и использованием лямбда-выражения, следует всегда предпочитать использование ссылки на метод.

📲 Мы в MAX

👉@BookJava

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

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

👩‍💻 Ваши Java-приложения под нагрузкой едва дышат? Профилирование и оптимизация кода остаются за скобками?

🎯 Курс «Java Developer. Advanced» от OTUS — это глубокое погружение в устройство JVM, байткод, сборщики мусора, профилирование и оптимизацию в облаке.
Наши эксперты-практики покажут, как выбрать GC, снять дамп памяти и обнаружить утечки, как профилировать “горячие” места, настраивать интеграцию с Prometheus & Grafana и деплоить сервисы в Kubernetes.

✔️ Вы научитесь обосновывать выбор JVM-имплементации, анализировать heap-дампы, синхронизировать потоки, использовать Reactor и неблокирующие I/O, проектировать метрики и трассировку.

➡️ Пройдите короткий тест и присоединяйтесь к группе: https://vk.cc/cRBJWK

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

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

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

Микросервисы на основе событий с Kafka Streams и Spring Boot

Всем привет! Это моя первая статья на Habr, так что не судите строго за стиль, а вот по содержанию буду рад любой конструктивной критике.

Статья основана на публикациях Confluent о том, как можно реализовать микросервисную архитектуру на основе событий с помощью Kafka Streams и KSQL.

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

📲 Мы в MAX

👉@BookJava

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

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

Совет 💡

Добавьте в JDBC URL свойство ApplicationName (зависит от БД, не в каждой БД оно есть!). Таким образом, в списке сессий вместо имени JDBC-драйвера будет отображаться имя набора. Это поможет при поиске неисправностей, когда несколько приложений подключаются к одной и той же БД.

📲 Мы в MAX

👉@BookJava

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

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

🎯 Открытый урок «Linq на практике».

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

На вебинаре будут рассмотрены:
✔️ синтаксис операторов linq;
✔️синтаксис компараторов, применяемых в linq-запросах;
✔️примеры linq-запросов для наиболее популярных коллекций.

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

Что вы получите:
- вы сможете писать свои linq-запросы, опираясь на синтаксис linq.Будете знать разницу при применении тех или иных методов в рамках написания linq-запросов.

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

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

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

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

🚀 В чем разница между HashMap и Hashtable в Java?

Если вы работаете с Java, то наверняка сталкивались с HashMap и Hashtable. Оба используются для хранения пар "ключ-значение", но между ними есть важные различия. Давайте разберемся!

1. Синхронизация (Потокобезопасность)
- Hashtable:
- Синхронизирован (потокобезопасен). Все его методы синхронизированы, то есть только один поток может работать с ним одновременно.
- Это делает Hashtable безопасным для многопоточных сред, но может снижать производительность в однопоточных сценариях.
- HashMap:
- Не синхронизирован (не потокобезопасен). Несколько потоков могут обращаться к нему одновременно, что может привести к проблемам в многопоточных средах.
- Для потокобезопасности можно использовать Collections.synchronizedMap(new HashMap<>()) или ConcurrentHashMap.


2. Null-ключи и Null-значения
- Hashtable:
- Не позволяет использовать null в качестве ключа или значения. Попытка добавить null вызовет NullPointerException.
- HashMap:
- Разрешает один null - ключ и множество null -значений.


3. Производительность
- Hashtable:
- Медленнее из-за накладных расходов на синхронизацию.
- HashMap:
- Быстрее в однопоточных средах, так как не синхронизирован.


4. Наследие
- Hashtable:
- Считается устаревшим классом (появился в Java 1.0). Не является частью Java Collections Framework.
- HashMap:
- Часть Java Collections Framework (появился в Java 1.2). Более современный и широко используемый.


5. Итерация
- Hashtable:
- Использует Enumeration для перебора ключей и значений.
- HashMap:
- Использует Iterator, который более гибкий и позволяет удалять элементы во время перебора.


6. Наследование
- Hashtable:
- Наследуется от класса Dictionary (абстрактный класс, который сейчас считается устаревшим).
- HashMap:
- Наследуется от AbstractMap, который является частью Java Collections Framework.


7. Рекомендации по использованию
- Используйте HashMap, если:
- Работаете в однопоточной среде.
- Нужна высокая производительность.
- Требуется поддержка null-ключей или значений.
- Используйте Hashtable, если:
- Нужна потокобезопасность в многопоточной среде.
- Однако в современной Java ConcurrentHashMap предпочтительнее, так как он обеспечивает лучшую производительность и масштабируемость.


Пример кода

Hashtable:


Hashtable<String, Integer> hashtable = new Hashtable<>();
hashtable.put("one", 1);
hashtable.put("two", 2);
// hashtable.put(null, 3); // Выбросит NullPointerException
System.out.println(hashtable);


HashMap:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
hashMap.put(null, 3); // Разрешено
System.out.println(hashMap);


Итоговая таблица

| Особенность | Hashtable | HashMap |
|-------------------------|---------------------------------|-------------------------------|
| Синхронизация | Синхронизирован | Не синхронизирован |
| Null-ключи/значения | Запрещены | Разрешены |
| Производительность | Медленнее | Быстрее |
| Наследие | Устаревший (Java 1.0) | Современный (Java 1.2) |
| Итерация | Enumeration | Iterator |
| Наследование | Наследует Dictionary | Наследует AbstractMap |

💡Совет: В современной разработке на Java HashMap используется чаще. Если нужна потокобезопасность, лучше выбрать ConcurrentHashMap, а не Hashtable.

📲 Мы в MAX

👉@BookJava

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

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

Дорогие друзья, с Новым Годом!!!

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

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

Spring Boot Tutorial | Полный курс

В этом учебном пособии по Spring Boot рассказывается о том, как начать работу с Spring Boot и Java.

00:00 Intro
01:00 Quick Word
02:12 Spring Boot Overview
03:44 Project Overview
04:28 Spring Initializr
08:05 IntelliJ
10:29 Starting The Server
14:03 Simple API with Spring Boot
18:06 Student Class
23:19 API Layer
26:38 Business Layer
29:08 Dependency Injection
32:47 Properties file
36:15 Creating and Connecting to Database
39:48 JPA and @ Entity
42:35 JPA in Action
45:52 Amigoscode Database Courses
47:35 JPA Repository
52:20 Saving Students
58:49 @ Transient
01:03:01 Post Mapping
01:08:00 Writing Business Logic
01:12:43 Testing Post Request
01:15:35 Deleting Students
01:21:33 Exercise
01:22:53 Solution
01:26:54 Testing
01:29:41 Packaging and Running Application
01:34:52 Next steps

источник

📲 Мы в MAX

👉@BookJava

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

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

🚀 Функциональные интерфейсы: Level Up

В первой части мы разобрали «Великолепную четверку» (Predicate, Consumer, Supplier, Function). Но что делать, если нужно принять два аргумента? Или если тип входа и выхода совпадает, и лень писать лишний код?

Для этого в Java есть Bi-версии и Операторы.

👯 Семейство «Bi» (Два аргумента)

Стандартные интерфейсы принимают только один параметр. Если вам нужно обработать пару значений (например, ключ и значение из Map), используйте приставку Bi.

1. BiPredicate <T, U>
💙 Метод: boolean test(T t, U u)
💙 Пример: Проверить, что длина строки T больше числа U.


2. BiConsumer <T, U>
💙 Метод: void accept(T t, U u)
💙 Пример: map.forEach((k, v) -> ...) - классический пример использования.


3. BiFunction <T, U, R>
💙 Метод: R apply(T t, U u)
💙 Пример: Сложить число T и число U, получить результат R.



🔄 Семейство «Operator» (Один и тот же тип)

Часто бывает, что вы преобразуете объект, не меняя его тип (String -> String, int -> int). Писать Function<String, String> - слишком длинно.

1. UnaryOperator <T>
💙 Наследник Function<T, T>.
💙 Пример: str -> str.toUpperCase() (принимает строку, возвращает строку).


2. BinaryOperator <T>
💙 Наследник BiFunction<T, T, T>.
💙 Пример: (a, b) -> a + b (два числа на вход, одно число на выход). Именно он используется в Stream.reduce.


⚡ Осторожно с боксингом!

Дженерики (<T>) работают только с объектами. Если вы используете Function<Integer, Integer> для математики, Java будет постоянно распаковывать и запаковывать int в Integer, что бьет по производительности.

Для примитивов есть свои спецназовцы:

💙 IntPredicate, LongConsumer, DoubleFunction и т.д.
💙 Правило: Если работаете с числами - всегда ищите примитивный аналог интерфейса.

💻 Пример в коде


import java.util.function.*;

public class AdvancedLambdas {
public static void main(String[] args) {
// 1. BinaryOperator: объединяем две строки
BinaryOperator<String> concat = (s1, s2) -> s1 + " " + s2;
System.out.println(concat.apply("Hello", "Java"));

// 2. BiPredicate: проверяем, начинается ли строка с префикса
BiPredicate<String, String> startsWith = (str, prefix) -> str.startsWith(prefix);
System.out.println(startsWith.test("Telegram", "Tele")); // true

// 3. IntUnaryOperator: работаем с примитивами без лишних объектов
IntUnaryOperator square = x -> x * x;
System.out.println(square.applyAsInt(5)); // 25
}
}



🔥 Итог

💙 Нужно 2 аргумента? Ищите Bi.
💙 Тип входа и выхода совпадает? Ищите Operator.
💙 Работаете с int/long/double? Ищите интерфейсы с префиксом типа.

#Java #AdvancedJava #FunctionalProgramming

📲 Мы в MAX

👉@BookJava

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

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

Использование метода String.join

Метод String.join можно использовать для объединения строк с заданным разделителем.


List<String> items = Arrays.asList("Apple", "Banana", "Cherry");
String result = String.join(", ", items);
System.out.println(result); // Output: Apple, Banana, Cherry


📲 Мы в MAX

👉@BookJava

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

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

⌨️ Открытый урок «Тестирование Spring приложений. Интеграционные тесты с контекстом. Тестирование слоя репозиториев и сервисов».

🗓 25 декабря в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Разработчик на Spring Framework».

Интеграционные тесты в Spring: тестовый контекст, репозитории (JDBC/JPA), сервисы и транзакции.

На вебинаре:
✔️Особенности интеграционных тестов с поднятием контекста Spring.
✔️Тестирование слоя репозиториев: JDBC и JPA.
✔️Работа с транзакциями на сервисном слое и подходы к тестированию.

Кому будет полезно:
Backend-разработчикам на Java, начинающим осваивать тестирование Spring-приложений.

Что вы получите:
Разберётесь в базе интеграционного тестирования со Spring-контекстом и сможете написать простые тесты для репозиториев и сервисов.

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

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

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

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

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

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

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

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

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

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

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

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

Использование лямбда-выражений и Streams:
Лямбда-выражения и streams делают код более лаконичным и читаемым.


List<String> names = Arrays.asList("John", "Jane", "Jack", "Doe");
names.stream()
.filter(name -> name.startsWith("J"))
.map(String::toUpperCase)
.forEach(System.out::println);


📲 Мы в MAX

👉@BookJava

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

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

Совет

По умолчанию при обновлении сущности Hibernate обновляет все ее поля. Вы можете использовать аннотацию @DynamicUpdate на объекте
@Entity и Hibernate будет обновлять только те столбцы, которые изменились.



📲 Мы в MAX

👉@BookJava

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

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

Использование Optional для избежания NullPointerException:
Optional — это контейнер, который может содержать или не содержать ненулевое значение.


Optional<String> optional = Optional.ofNullable(getValue());
optional.ifPresentOrElse(
value -> System.out.println("Value is present: " + value),
() -> System.out.println("Value is absent")
);


📲 Мы в MAX

👉@BookJava

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

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

Совет по Java 💡

Использование try-with-resources для автоматического управления ресурсами
Оператор try-with-resources гарантирует, что каждый ресурс будет закрыт в конце оператора.


try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}


📲 Мы в MAX

👉@BookJava

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

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

Многопоточность

Как можно создать потоки в Java?
Как устроить Deadlock, а затем уйти от взаимной блокировки навсегда
Два самых полезных слова в многопоточности join() и Future

источник

📲 Мы в MAX

👉@BookJava

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

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

Неожиданное введение в Spring MVC

Spring MVC кажется сложным — пока не поймёшь, как он вырос из обычных сервлетов. На вебинаре шаг за шагом соберём свой первый фреймворк и разберёмся, зачем нужен MVC.

Приглашаем на открытый урок.
📅 Встречаемся 24 ноября в 20:00 мск.

Расскажет Александр Оруджев — Senior Software Engineer. Встречаемся на бесплатном практическом уроке от OTUS, где вы вместе с опытным экспертом разберете:
• как сервлеты превратились в контроллеры;
• что делает Spring под капотом;
• как построить собственный мини-MVC и понять принципы работы фреймворка.

После вебинара вы:
— поймёте архитектуру MVC без заучивания;
— перестанете бояться Spring MVC и начнёте использовать его осознанно;
— сделаете первый шаг к системному пониманию backend-разработки.

24 ноября в 20:00 открытый урок проходит в преддверие старта курса «Разработчик на Spring Framework». Все участники получат скидку на обучение.

👉 Регистрация бесплатная, но количество мест ограничено — успей занять своё место: https://vk.cc/cRv9kP

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

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

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

Совет 🚀 Spring Retry 🚀

Spring Retry предлагает возможность автоматического повторного выполнения неудачной операции. 🔥

https://github.com/spring-projects/spring-retry

📲 Мы в MAX

👉@BookJava

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