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


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

РКН clck.ru/3KoGeP
Download Telegram
🗺 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
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍6
🛒 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
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4