Почему для операции flatMap требуется функция, возвращающая Stream, а не функция, возвращающая Collection? По какой-то конкретной причине это заставляет пользователя выполнять преобразование потока вручную?
Читая пример исходного кода, я вижу, что таким образом совместимость может быть расширена до массивов, но не приведет ли перегрузка flatMap к тому же результату?
// Java 8 source code example:
Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
В каких случаях лучше явно указать процесс потоковой передачи?
Пример: почему я вынужден это делать
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> flatList = map.entrySet().stream().flatMap(e -> e.getValue().stream()).collect(Collectors.toList());
вместо этого?
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> flatList = map.entrySet().stream().flatMap(Map.Entry::getValue).collect(Collectors.toList());
Что, если вы захотите вернуть другой поток, который не представлен в виде массива или коллекции? Допустим, я хочу вручную разбить объект на поток значений — конечно, я мог бы сначала создать коллекцию, но это может быть накладным. Простое требование вернуть поток очень гибко и не намного сложнее.
Потоки и коллекции не взаимозаменяемы. Но вы можете транслировать любую коллекцию, поэтому имеет смысл принять более гибкую конструкцию.
@Thomas, да, это не добавляет намного больше кода, мне просто было интересно, почему он был разработан таким образом, потому что большую часть времени это просто заставляет меня писать дополнительный .stream(), я думаю, ваш аргумент имеет смысл, Спасибо!
Потоковая передача через другую коллекцию, похоже, не является предполагаемым основным вариантом использования, по крайней мере, реализация не оптимизирована для этого сценария. Лучше всего он работает с довольно небольшими подпотоками, которые могут быть получены из коллекций, но также могут быть получены из таких функций, как arg -> condition? Stream.of(x, y, z): null
или arg -> condition? Stream.of(arg): Stream.of(arg, anotherObject)
Кстати, вместо .flatMap(line -> Stream.of(line.split(" +")))
я бы предпочел использовать .flatMap(Pattern.compile(" +")::splitAsStream)
По моему опыту, он часто используется с коллекциями, но часто перед сведением выполняются дополнительные операции, например. .flatMap(list -> list.stream().limit(3))
Кстати, если вы считаете, что это чище, вы можете заменить .flatMap(e -> e.getValue().stream())
на .map(Entry::getValue).flatMap(List::stream)
.
Почему для операции
flatMap()
требуется функция, которая возвращаетStream
, а не функция, которая возвращаетCollection
?
Тому есть много причин:
Поток — это средство итерации, т. е. мы не храним данные в потоке, его цель — лениво перебирать много по источнику данных, который может быть String
, массивом, потоком ввода-вывода и т. д.
Во-вторых, потоковые операции делятся на две группы: терминальные, предназначенные для выдачи результата и прекращения выполнения потокового конвейера (т. . Промежуточные операции всегда ленивы. Поток берет элементы из источника один за другим и обрабатывает их лениво, т.е. операции происходят только тогда, когда это необходимо. Не делайте новый поток с цепочкой вложенных for
-циклов, они ведут себя иначе. Каждая промежуточная операция создает новый поток.
Вот цитата из документации API:
Потоки отличаются от коллекций несколькими способами:
Нет хранилища. Поток — это не структура данных, в которой хранятся элементы; вместо этого он передает элементы из источника, такого как структура данных, массив, функция-генератор или канал ввода-вывода через конвейер вычислительных операций.
Поиск лени. Многие потоковые операции, такие как фильтрация, сопоставление или удаление дубликатов, могут быть реализованы лениво, подвергая возможности для оптимизации. Например, «найти первую строку с тремя последовательными гласными" не нужно проверять все входные строки. Потоковые операции делятся на промежуточные (Stream-производящие) операции и терминальные (производящие ценность или побочные эффекты) операции. Промежуточные операции всегда ленивы.
Collectoin
), для flatMap()
разумно ожидать данные в предсказуемой унифицированной форме, а не в виде массива, коллекции, итерации и т. д., а другого внутреннего итератора, то есть другой поток, так что очевидно, как с этим бороться.Любой вариант, который вы можете использовать, будет менее интуитивным. Если бы flatMap()
был реализован таким образом, что ожидал бы функцию, производящую Collection
, как бы вы поступили со строками, массивами, потоками ввода-вывода, различными реализациями Iterable
? Сбрасывая данные в коллекцию - это не вариант. Та же проблема возникнет, если мы представим, что flatMap()
требуется Iterable
, как мы будем производить Iterable
из String
? Потоки разработаны, чтобы быть универсальными.
Я подозреваю, что ваше суждение о flatMap()
предвзято, потому что вы к нему не привыкли. Когда вы принимаете идею о том, что Stream является внутренним итератором, тот факт, что операция выравнивания данных ожидает функцию, создающую другой итератор, будет восприниматься как более интуитивно понятный.
может быть¹, потому что
flatMap
сам по себе предназначен для использования вStream
, что-то вроде согласованности - одна из характеристикStream
заключается в том, чтобы запускать только те части, которые необходимы, когда и если они нужны - создание коллекции позволит избежать этого. || ¹ Я не являюсь ни разработчиком, ни спецификатором, лучше спросить кого-нибудь, кто занимается его разработкой