flatMap для вложенных коллекций
Сглаживайте вложенные списки, цепочки Optional и структуры из строк файлов с помощью flatMap.
«flatMap для вложенных коллекций» — бесплатный урок Java Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Проблема вложенных коллекций
Когда каждый элемент потока преобразуется в другую коллекцию, map создаёт Stream<List<T>>. flatMap объединяет внутренние потоки в один плоский Stream<T>.
List<List<Integer>> nested = List.of(List.of(1,2), List.of(3,4), List.of(5));
// With map:
Stream<List<Integer>> s = nested.stream().map(l -> l); // Stream<List<Integer>>
// With flatMap:
Stream<Integer> flat = nested.stream().flatMap(List::stream); // Stream<Integer>
flat.forEach(System.out::println); // 1 2 3 4 5flatMap и map
map(f) применяет f к каждому элементу и оборачивает результат. flatMap(f) применяет f, возвращающую поток, а затем объединяет все эти потоки в один.
// map: List<String> -> Stream<Stream<Character>>
Stream<Stream<Character>> nested = List.of("hi","bye").stream()
.map(s -> s.chars().mapToObj(c -> (char)c));
// flatMap: List<String> -> Stream<Character>
Stream<Character> flat = List.of("hi","bye").stream()
.flatMap(s -> s.chars().mapToObj(c -> (char)c));Объединение заказов и элементов
Классический случай: у каждого заказа есть список элементов. Получите плоский поток всех элементов из всех заказов.
List<String> allItems = orders.stream()
.flatMap(order -> order.getItems().stream())
.collect(Collectors.toList());
System.out.println(allItems);flatMap с Optional
Используйте stream() для Optional (Java 9+), чтобы преобразовать его в поток из 0 или 1 элемента. Затем flatMap сворачивает Stream<Optional<T>> в Stream<T>.
List<Optional<String>> maybes = List.of(Optional.of("a"), Optional.empty(), Optional.of("c"));
List<String> values = maybes.stream()
.flatMap(Optional::stream) // Java 9+
.collect(Collectors.toList());
System.out.println(values); // [a, c]Чтение всех строк из нескольких файлов
flatMap упрощает объединение всех строк из списка файлов в один поток без вложенных циклов.
List<Path> files = List.of(Path.of("a.txt"), Path.of("b.txt"));
List<String> allLines = files.stream()
.flatMap(p -> {
try { return Files.lines(p); }
catch (IOException e) { return Stream.empty(); }
})
.collect(Collectors.toList());Разбиение строк на слова
Разбейте каждое предложение на слова и объедините все слова в один поток для подсчёта частоты слов.
List<String> sentences = List.of("hello world", "java streams rock");
Map<String, Long> freq = sentences.stream()
.flatMap(s -> Arrays.stream(s.split("\\s+")))
.collect(Collectors.groupingBy(w -> w, Collectors.counting()));
System.out.println(freq);flatMap с Map.entrySet
Преобразуйте map категорий, содержащий списки элементов, в поток всех элементов.
Map<String, List<String>> catalog = Map.of(
"fruit", List.of("apple","banana"),
"veg", List.of("carrot","pea"));
List<String> all = catalog.values().stream()
.flatMap(List::stream)
.sorted()
.collect(Collectors.toList());
System.out.println(all); // [apple, banana, carrot, pea]Предотвращение NullPointerException в flatMap
Если функция может вернуть null вместо потока, выполните проверку на null или верните Stream.empty(), чтобы избежать NullPointerException.
departments.stream()
.flatMap(dept -> dept.getEmployees() == null
? Stream.empty()
: dept.getEmployees().stream())
.forEach(System.out::println);Подсчёт уникальных слов с flatMap
Объедините flatMap, distinct и count для лаконичной обработки данных.
long distinctWords = sentences.stream()
.flatMap(s -> Arrays.stream(s.toLowerCase().split("[^a-z]+")))
.filter(w -> !w.isEmpty())
.distinct()
.count();
System.out.println("Distinct: " + distinctWords);flatMapToInt для потоков примитивов
Используйте flatMapToInt, flatMapToLong и flatMapToDouble, чтобы избежать упаковки при преобразовании в потоки примитивов.
int totalQuantity = orders.stream()
.flatMapToInt(order -> order.getItems().stream().mapToInt(Item::getQuantity))
.sum();
System.out.println("Total qty: " + totalQuantity);Примечание о производительности
Каждый вызов flatMap добавляет уровень потока. Для очень больших наборов данных с множеством небольших вложенных коллекций рассмотрите итеративные подходы или Spliterator, чтобы уменьшить накладные расходы на создание объектов.
Быстрая проверка
Чем flatMap отличается от map?
Итоги
flatMap преобразует каждый элемент в поток и объединяет все потоки в один. Используйте его для выравнивания вложенных коллекций, объединения Optional, разделения строк и чтения нескольких файлов. Используйте flatMapToInt, чтобы избежать упаковки.
Часто задаваемые вопросы
Урок «flatMap для вложенных коллекций» бесплатный?
Да — полный текст урока «flatMap для вложенных коллекций» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «flatMap для вложенных коллекций»?
Сглаживайте вложенные списки, цепочки Optional и структуры из строк файлов с помощью flatMap. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «flatMap для вложенных коллекций»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- flatMap для вложенных коллекций
- Параллельные потоки: производительность и подводные камни
- Spliterator: разделение для параллельной обработки
- Бесконечные потоки с iterate и generate