Для чего используется операция `flatMap` в Java Streams?

«Для чего используется операция `flatMap` в Java Streams?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Операция flatMap используется в Java Stream API для преобразования каждого элемента потока в новый поток (Stream), а затем «склеивания» (выравнивания) всех этих потоков в один результирующий поток. Это необходимо, когда одно входное значение может соответствовать нулю, одному или нескольким выходным значениям.

Типичные сценарии использования:

  1. Преобразование вложенных коллекций в плоский список.

    List<List<String>> nestedLists = List.of(
        List.of("a", "b", "c"),
        List.of("d", "e")
    );
    List<String> flatList = nestedLists.stream()
        .flatMap(List::stream) // Преобразуем каждый List в Stream<String>
        .collect(Collectors.toList()); // Результат: ["a", "b", "c", "d", "e"]
  2. Разделение элемента на несколько. Например, разбиение строки на слова.

    List<String> words = List.of("Hello World", "Java Streams");
    List<String> individualWords = words.stream()
        .flatMap(line -> Arrays.stream(line.split(" "))) // Stream<String> для каждой строки
        .collect(Collectors.toList()); // ["Hello", "World", "Java", "Streams"]
  3. Фильтрация Optional значений. flatMap удобен для цепочки операций, возвращающих Optional, избегая вложенных if.

    Optional<String> result = Optional.of("value")
        .flatMap(v -> Optional.of(v.toUpperCase())) // Преобразует Optional<String> в Optional<String>
        .flatMap(v -> v.isEmpty() ? Optional.empty() : Optional.of(v));
  4. Реактивное программирование. Аналогичная операция flatMap используется в проекте Reactor и RxJava для асинхронной обработки потоков данных, где каждый элемент может запускать асинхронную операцию.