0Pricing
Java Academy · Урок

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 5

flatMap и 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 — локальная установка не требуется.

Все уроки этого курса

  1. flatMap для вложенных коллекций
  2. Параллельные потоки: производительность и подводные камни
  3. Spliterator: разделение для параллельной обработки
  4. Бесконечные потоки с iterate и generate
← Назад к Java Academy