Ответ
Оба метода используются для работы с вложенными структурами в потоках, но имеют разные сигнатуры и применения.
flat() — это метод интерфейса Stream, который существует только для специализированных потоков примитивов (IntStream, LongStream, DoubleStream). Он преобразует поток потоков примитивов в один "плоский" поток.
// flat() для IntStream
Stream<IntStream> streamOfIntStreams = Stream.of(IntStream.of(1,2), IntStream.of(3,4));
IntStream flatIntStream = streamOfIntStreams.flatMapToInt(s -> s); // Используется flatMapToInt
// ИЛИ, если у нас уже есть IntStream
IntStream.of(1,2,3).flatMap(...) // flatMap для примитивов
flatMap() — это основной и чаще используемый метод в Stream<T>. Он выполняет две операции:
- Map (отображение): Применяет функцию к каждому элементу, которая возвращает новый поток (
Stream<R>). - Flatten ("выравнивание"): Объединяет все полученные потоки в один результирующий поток.
// flatMap() для Stream<String>
List<List<String>> listOfLists = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d")
);
List<String> flatList = listOfLists.stream()
.flatMap(Collection::stream) // List<String> -> Stream<String>
.collect(Collectors.toList()); // Результат: ["a", "b", "c", "d"]
// Другой пример: разбить строки на слова
List<String> sentences = Arrays.asList("Hello world", "Java Streams");
List<String> words = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" "))) // String -> Stream<String>
.collect(Collectors.toList()); // ["Hello", "world", "Java", "Streams"]
Сравнение
- Назначение:
flat()— для "выравнивания" потоков примитивов.flatMap()— для преобразования элемента в поток и последующего объединения всех потоков. - Использование:
flatMap()универсален и применяется в 99% случаев для работы сStream<T>.flat()— узкоспециализированный метод. - Ключевая идея
flatMap: Решает проблемуmap(), который изStream<List<T>>сделал быStream<Stream<T>>.flatMapсразу возвращаетStream<T>.