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


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

РКН clck.ru/3KoGeP
Download Telegram
🍒 Магия двойного двоеточия: 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
Please open Telegram to view this post
VIEW IN TELEGRAM
👍53
🗺 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