Что такое flatMap в Stream API?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
flatMap в Stream API
flatMap — это промежуточная операция в Stream API, которая применяет функцию-маппер к каждому элементу потока и затем объединяет (flattens) все полученные потоки в один результирующий поток. Название происходит от сочетания "flat" (плоский) и "map" (преобразование).
Сигнатура метода
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
Метод принимает функцию, которая преобразует элемент типа T в Stream типа R, а затем все эти потоки объединяются в единый поток результирующих элементов.
Как работает flatMap
Отличие flatMap от обычного map заключается в том, что map просто преобразует элемент, а flatMap позволяет каждому элементу генерировать несколько результатов, которые затем объединяются:
// map: преобразует каждый элемент в один новый элемент
List<Integer> numbers = Arrays.asList(1, 2, 3);
Stream<Integer> mapped = numbers.stream()
.map(x -> x * 2); // 2, 4, 6
// flatMap: каждый элемент может генерировать несколько элементов
Stream<Integer> flattened = numbers.stream()
.flatMap(x -> Stream.of(x, x * 2)); // 1, 2, 2, 4, 3, 6
Практические примеры
Пример 1: Развертывание списков
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d"),
Arrays.asList("e", "f")
);
List<String> flattened = listOfLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
// Результат: [a, b, c, d, e, f]
Пример 2: Генерирование нескольких значений на один элемент
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<Integer> result = numbers.stream()
.flatMap(x -> Stream.of(x, x * x, x * x * x))
.collect(Collectors.toList());
// Результат: [1, 1, 1, 2, 4, 8, 3, 9, 27]
Пример 3: Преобразование String в символы
List<String> words = Arrays.asList("Hello", "World");
List<String> chars = words.stream()
.flatMap(word -> word.chars().boxed().map(String::valueOf))
.collect(Collectors.toList());
// Результат: [H, e, l, l, o, W, o, r, l, d]
flatMap vs map
List<Integer> numbers = Arrays.asList(1, 2);
// map возвращает Stream<Stream<Integer>>
Stream<Stream<Integer>> mapResult = numbers.stream()
.map(x -> Stream.of(x, x * 2));
// flatMap возвращает Stream<Integer>
Stream<Integer> flatMapResult = numbers.stream()
.flatMap(x -> Stream.of(x, x * 2));
Другие варианты flatMap
// flatMapToInt, flatMapToLong, flatMapToDouble
List<String> numbers = Arrays.asList("1,2,3", "4,5,6");
int sum = numbers.stream()
.flatMapToInt(str -> Arrays.stream(
Arrays.stream(str.split(","))
.mapToInt(Integer::parseInt)
.toArray()
))
.sum();
Важные особенности
- Ленивость вычисления: flatMap не выполняется до терминальной операции (collect, forEach и т.д.)
- Порядок элементов: элементы обрабатываются в порядке, заданном функцией mapper
- Производительность: flatMap может быть менее эффективен, чем несколько операций map, из-за создания промежуточных потоков
- Null-safety: если mapper вернет null вместо Stream, будет NullPointerException
flatMap — мощный инструмент для работы с вложенными структурами данных и преобразования коллекций в Stream API.