Что такое flatMap?

«Что такое flatMap?» — вопрос из категории Java, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

flatMap — это операция, доступная в Java Stream API и других библиотеках функционального программирования, которая выполняет две задачи последовательно:

  1. Преобразование (Map): Применяет заданную функцию к каждому элементу потока (стрима). Эта функция должна возвращать новый поток (Stream) для каждого элемента.
  2. Выравнивание (Flatten): Объединяет ("склеивает") все полученные потоки в один результирующий поток.

Проще говоря, flatMap преобразует поток элементов типа A в поток элементов типа B, где каждый элемент A может порождать ноль, один или несколько элементов B.

Пример: Разбиение строк на слова

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FlatMapExample {
    public static void main(String[] args) {
        List<String> sentences = Arrays.asList(
            "Hello world",
            "Java Stream API",
            "flatMap example"
        );

        List<String> words = sentences.stream()        // Stream<String>
            .map(sentence -> sentence.split(" "))     // Stream<String[]> (плохо, вложенная структура)
            .flatMap(Arrays::stream)                  // Stream<String> (выравниваем массив в поток)
            .collect(Collectors.toList());

        System.out.println(words); 
        // [Hello, world, Java, Stream, API, flatMap, example]
    }
}

Отличие от map:

  • map: Преобразует Stream<A> в Stream<B> по принципу 1 к 1.
  • flatMap: Преобразует Stream<A> в Stream<B> по принципу 1 ко многим, а затем объединяет результаты.

Применение в тестировании (QA):

  • Обработка тестовых данных: Генерация комплексных наборов тестовых данных из простых входных параметров (например, создание всех комбинаций параметров для Data-Driven Testing).
  • Анализ логов или ответов API: Когда тесту нужно обработать вложенные структуры данных (например, извлечь все ID заказов из списка пользователей).
    // Предположим, у User есть метод getOrderIds(), возвращающий List<Long>
    List<Long> allOrderIds = testUsers.stream()
        .flatMap(user -> user.getOrderIds().stream())
        .toList();
  • Работа с Optional: Optional.flatMap используется для цепочки операций, которые сами возвращают Optional, избегая вложенности Optional<Optional<T>>.