В Java 8, в чем разница Stream.map()
и Stream.flatMap()
методы?
java
java-8
java-stream
cassiomolin
источник
источник
map :: Stream T -> (T -> R) -> Stream R
,flatMap :: Stream T -> (T -> Stream R) -> Stream R
.<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
.map
лямбда-преобразовательR
aflatMap
'возвращает лямбда-отображение mapper aStream
ofR
(Stream<R>
). Потоки, возвращаемыеflatMap
преобразователем, эффективно сцепляются. В противном случае обаmap
иflatMap
возвращаютсяStream<R>
; разница , что возвращается картограф лямбда,R
противStream<R>
.Ответы:
Оба
map
иflatMap
могут быть применены к a,Stream<T>
и они оба возвращают aStream<R>
. Разница заключается в том, чтоmap
операция создает одно выходное значение для каждого входного значения, тогда какflatMap
операция создает произвольное число (ноль или более) значений для каждого входного значения.Это отражено в аргументах каждой операции.
map
Операция занимаетFunction
, которая вызывается для каждого значения во входном потоке и производит одно значение результата, который посылается в выходной поток.flatMap
Операция принимает функцию , которая концептуально хочет потреблять одно значение и произвести произвольное число значений. Тем не менее, в Java для метода трудно возвращать произвольное количество значений, поскольку методы могут возвращать только ноль или одно значение. Можно представить API, в котором функция mapperflatMap
принимает значение и возвращает массив илиList
значений, которые затем отправляются на выход. Учитывая, что это библиотека потоков, особенно удачным способом представления произвольного числа возвращаемых значений является то, что сама функция mapper возвращает поток! Значения из потока, возвращаемого преобразователем, выводятся из потока и передаются в выходной поток. «Скопления» значений, возвращаемых при каждом вызове функции преобразования, вообще не различаются в выходном потоке, поэтому говорят, что вывод «сглажен».Типичное использование для функции mapper
flatMap
для возврата,Stream.empty()
если она хочет отправить нулевые значения, или что-то вроде,Stream.of(a, b, c)
если она хочет вернуть несколько значений. Но, конечно, любой поток может быть возвращен.источник
flatMap
операция является полной противоположностью плоской. Еще раз, оставьте это для Компьютерных Ученых, чтобы перевернуть термин на его голову. Как функция, являющаяся «прозрачной», то есть вы не можете видеть ничего, что она делает, только результаты, в то время как в разговорной речи вы говорите, что хотите, чтобы процесс был прозрачным, означает, что вы хотите видеть каждую его часть.Stream.flatMap
Как можно догадаться по его названию, это сочетание amap
иflat
операции. Это означает, что вы сначала применяете функцию к своим элементам, а затем выравниваете ее.Stream.map
только применяет функцию к потоку без выравнивания потока.Чтобы понять, в чем состоит уплощение потока, рассмотрим такую структуру,
[ [1,2,3],[4,5,6],[7,8,9] ]
которая имеет «два уровня». Уплощение означает преобразование в структуру «одного уровня»[ 1,2,3,4,5,6,7,8,9 ]
.источник
Я хотел бы привести 2 примера, чтобы получить более практическую точку зрения:
Первый пример, использующий карту:
Ничего особенного в первом примере, a
Function
применяется для возвратаString
в верхний регистр.Второй пример, использующий
flatMap
:Во втором примере передается поток списка. Это не поток целых чисел!
Если необходимо использовать функцию преобразования (через карту), то сначала поток должен быть сведен к чему-то другому (поток целых чисел).
Если flatMap удален, то возвращается следующая ошибка: Оператор + не определен для типа (ов) аргумента List, int.
Нельзя применить + 1 к списку целых чисел!
источник
Stream<Integer>
а не потокInteger
.Пожалуйста, пройдите по почте полностью, чтобы получить ясное представление,
карта против плоской карты:
Чтобы вернуть длину каждого слова из списка, мы сделаем что-то вроде ниже.
Короткая версия приведена ниже
Когда мы собираем два списка, приведенных ниже
Без плоской карты => [1,2], [1,1] => [[1,2], [1,1]] Здесь два списка размещены внутри списка, поэтому на выходе будет список, содержащий списки
С плоской картой => [1,2], [1,1] => [1,2,1,1] Здесь два списка сглаживаются и в список помещаются только значения, поэтому на выходе будет список, содержащий только элементы
В основном это объединяет все объекты в один
## Подробная версия была дана ниже: -
Например: -
Рассмотрим список [«STACK», «OOOVVVER»], и мы пытаемся вернуть список наподобие [«STACKOVER»] (возвращая только уникальные буквы из этого списка). Сначала мы бы сделали что-то подобное ниже, чтобы вернуть список [«STACKOVER»] из [«STACK», «ОООВВВЕР»]
Здесь проблема в том, что лямбда, переданная методу карты, возвращает массив String для каждого слова, поэтому поток, возвращаемый методом карты, на самом деле имеет тип Stream, но нам нужен Stream для представления потока символов, ниже изображение иллюстрирует проблема.
Рисунок А:
Вы можете подумать, что мы можем решить эту проблему, используя flatmap,
хорошо, давайте посмотрим, как решить эту проблему, используя map и Arrays.stream. Прежде всего вам понадобится поток символов вместо потока массивов. Существует метод с именем Arrays.stream (), который принимает массив и создает поток, например:
Выше все равно не работает, потому что теперь мы получаем список потоков (точнее, Stream>). Вместо этого мы должны сначала преобразовать каждое слово в массив отдельных букв, а затем превратить каждый массив в отдельный поток.
Используя flatMap, мы сможем решить эту проблему, как показано ниже:
flatMap будет выполнять сопоставление каждого массива не с потоком, а с содержимым этого потока. Все отдельные потоки, которые генерируются при использовании map (Arrays :: stream), объединяются в один поток. На рисунке B показан эффект использования метода flatMap. Сравните это с тем, что делает карта на рисунке A. Рисунок B
Метод flatMap позволяет заменить каждое значение потока другим потоком, а затем объединяет все созданные потоки в один поток.
источник
Ответ в одной строке:
flatMap
помогает сплющитьCollection<Collection<T>>
вCollection<T>
. Таким же образом, это также сгладитOptional<Optional<T>>
вOptional<T>
.Как видите,
map()
только с:Stream<List<Item>>
List<List<Item>>
и с
flatMap()
:Stream<Item>
List<Item>
Это результат теста из кода, использованного прямо ниже:
Используемый код :
источник
Функция, которую вы передаете
stream.map
, должна возвращать один объект. Это означает, что каждый объект во входном потоке приводит к точно одному объекту в выходном потоке.Функция, которую вы передаете,
stream.flatMap
возвращает поток для каждого объекта. Это означает, что функция может возвращать любое количество объектов для каждого входного объекта (включая ни одного). Результирующие потоки затем объединяются в один выходной поток.источник
Department
s в вашей организации. Каждый отдел имеет от 0 до nEmployee
с. Что вам нужно, это поток всех сотрудников. Ну так что ты делаешь? Вы пишете метод flatMap, который принимает отдел и возвращает поток его сотрудников.flatMap
? Я подозреваю, что это может быть случайным и не иллюстрирует ключевой вариант использования или причину, по которой онflatMap
существует. (Продолжение ниже ...)flatMap
является устранение ошибок, которые могут возникнуть при использованииmap
. Как вы обрабатываете случаи, когда один или несколько элементов в исходном наборе не могут быть сопоставлены с выходным элементом? Введение промежуточного набора (скажем,Optional
илиStream
) для каждого объекта вводаflatMap
позволяет исключить «недопустимые» объекты ввода (или так называемые «плохие яблоки» в духе stackoverflow.com/a/52248643/107158 ) из финальный сет.для карты у нас есть список элементов и (функция, действие) f так:
и для плоской карты у нас есть список элементов списка, и у нас есть (функция, действие) f, и мы хотим, чтобы результат был сведен:
источник
У меня такое ощущение, что большинство ответов здесь усложняют простую проблему. Если вы уже понимаете, как
map
работает, это должно быть довольно легко понять.Есть случаи, когда мы можем получить нежелательные вложенные структуры при использовании
map()
,flatMap()
метод предназначен для преодоления этого путем избежания переноса.Примеры:
1
Мы можем избежать использования вложенных списков, используя
flatMap
:2
где:
источник
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());
. Это должно бытьStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
В статье Oracle, посвященной Optional, подчеркивается это различие между картой и плоской картой:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
источник
Я не уверен, что должен ответить на этот вопрос, но каждый раз, когда я сталкиваюсь с кем-то, кто этого не понимает, я использую один и тот же пример.
Представь, что у тебя есть яблоко. А
map
превращает это яблоко,apple-juice
например, или в однозначное сопоставление.Возьмите то же самое яблоко и достаньте из него только семена, то есть то
flatMap
, что нужно, или одно ко многим , одно яблоко как вход, много семян как выход.источник
flatMap
случая, вы сначала собираете семена каждого яблока в отдельные пакеты, по одному пакету на яблоко, прежде чем выливать все пакеты в один пакет?flatmap
самом деле не ленивый, но с java-10 ленивыйflatMap + lazy
, держу пари, будут ответы.map () и flatMap ()
map()
Просто принимает Function лямбда-параметр, где T - элемент, а R - возвращаемый элемент, построенный с использованием T. В конце мы получим Stream с объектами типа R. Простой пример может быть:
Он просто берет элементы с 1 по 5 типа
Integer
, использует каждый элемент для создания нового элемента из типаString
со значением"prefix_"+integer_value
и печатает его.flatMap()
Полезно знать, что flatMap () принимает функцию, в
F<T, R>
которойT - это тип, из которого можно построить поток из / с . Это может быть List (T.stream ()), массив (Arrays.stream (someArray)) и т. Д. Все, из чего может быть получен поток в / или форме. в приведенном ниже примере у каждого разработчика много языков, поэтому dev. Languages - это список и будет использовать лямбда-параметр.
R - это результирующий поток, который будет построен с использованием T. Зная, что у нас есть много экземпляров T, у нас, естественно, будет много потоков из R. Все эти потоки из типа R теперь будут объединены в один «плоский» поток из типа R ,
пример
Примеры Бачири Тауфика, его ответ здесь прост и понятен. Просто для ясности, скажем так, у нас есть команда разработчиков:
каждый разработчик знает много языков:
Применение Stream.map () к dev_team для получения языков каждого разработчика:
даст вам эту структуру:
который в основном
List<List<Languages>> /Object[Languages[]]
. Не очень красиво и не похоже на Java8!с помощью
Stream.flatMap()
него можно «сгладить» вещи, поскольку он берет вышеупомянутую структуруи превращает ее в
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, что в основном может использоваться какList<Languages>/Language[]/etc
...так что в конце ваш код будет иметь больше смысла, как это:
или просто:
Когда использовать map () и flatMap () :
Используется,
map()
когда каждый элемент типа T из вашего потока должен отображаться / преобразовываться в один элемент типа R. Результатом является отображение типа (1 начальный элемент -> 1 конечный элемент) и новый поток элементов типа R возвращаетсяИспользуйте,
flatMap()
когда каждый элемент типа T из вашего потока должен отображаться / преобразовываться в Коллекции элементов типа R. Результатом является отображение типа (1 начальный элемент -> n конечных элементов) . Эти коллекции затем объединяются (или сплющиваются ) с новым потоком элементов типа R. Это полезно, например, для представления вложенных циклов .Pre Java 8:
Post Java 8
источник
Карта: - Этот метод принимает одну функцию в качестве аргумента и возвращает новый поток, состоящий из результатов, сгенерированных путем применения переданной функции ко всем элементам потока.
Давайте представим, у меня есть список целочисленных значений (1,2,3,4,5) и один интерфейс функции, логика которого является квадратом переданного целого числа. (е -> е * е).
вывод:-
Как видите, выход - это новый поток, значения которого являются квадратами значений входного потока.
http://codedestine.com/java-8-stream-map-method/
FlatMap: - Этот метод принимает одну функцию в качестве аргумента, эта функция принимает один параметр T в качестве входного аргумента и возвращает один поток параметра R в качестве возвращаемого значения. Когда эта функция применяется к каждому элементу этого потока, она создает поток новых значений. Все элементы этих новых потоков, сгенерированных каждым элементом, затем копируются в новый поток, который будет возвращаемым значением этого метода.
Давайте представим, у меня есть список предметов учеников, где каждый ученик может выбрать несколько предметов.
вывод:-
Как вы можете видеть, вывод - это новый поток, значения которого представляют собой совокупность всех элементов потоков, возвращаемых каждым элементом входного потока.
[S1, S2, S3] -> [{"история", "математика", "география"}, {"экономика", "биология"}, {"наука", "математика"}] -> принять уникальные предметы - > [экономика, биология, география, наука, история, математика]
http://codedestine.com/java-8-stream-flatmap-method/
источник
.map для отображения A -> B
он преобразует любой элемент
A
в любой элементB
. Javadoc.flatMap для А -> Поток <B> concatinating
он --1 преобразует любой элемент
A
вStream< B>
, а затем --2 объединяет все потоки в один (плоский) поток. JavadocПримечание 1: Хотя последний пример представляет собой поток примитивов (IntStream) вместо потока объектов (Stream), он все же иллюстрирует идею
.flatMap
.Примечание 2. Несмотря на имя, метод String.chars () возвращает целые числа. Таким образом, фактическая коллекция будет:
[100, 111, 103, 99, 97, 116]
где100
код'd'
,111
код'o'
и т. Д. Опять же, в иллюстративных целях, она представлена как [d, o, g, c, a, t].источник
Простой ответ
map
Операция может производитьStream
изStream
.EXStream<Stream<Integer>>
flatMap
операция будет только производитьStream
что-то. EXStream<Integer>
источник
Также хорошая аналогия может быть с C #, если вы знакомы с. В основном C #
Select
похож на Javamap
и C #SelectMany
JavaflatMap
. То же относится и к Kotlin для коллекций.источник
Это очень запутанно для начинающих. Основное различие заключается в
map
выделении одного элемента для каждой записи в списке иflatMap
в основном операцииmap
+flatten
. Чтобы быть более понятным, используйте flatMap, когда вам требуется более одного значения, например, когда вы ожидаете, что цикл возвратит массивы, flatMap будет действительно полезен в этом случае.Я написал блог об этом, вы можете проверить это здесь .
источник
Поток операций
flatMap
иmap
принять функцию в качестве ввода.flatMap
ожидает, что функция возвратит новый поток для каждого элемента потока и возвратит поток, который объединяет все элементы потоков, возвращаемых функцией для каждого элемента. Другими словами,flatMap
для каждого элемента из источника функция создаст несколько элементов. http://www.zoftino.com/java-stream-examples#flatmap-operationmap
ожидает, что функция вернет преобразованное значение и вернет новый поток, содержащий преобразованные элементы. Другими словами,map
для каждого элемента из источника функция создаст один преобразованный элемент. http://www.zoftino.com/java-stream-examples#map-operationисточник
flatMap()
также использует частичную ленивую оценку потоков. Он будет читать первый поток и только при необходимости перейдет к следующему потоку. Поведение подробно объясняется здесь: Гарантируется ли flatMap ленивость?источник
Если вы думаете
map()
как итерация (одноуровневыйfor
цикл),flatmap()
это двухуровневая итерация (как вложенныйfor
цикл). (Введите каждый повторяющийся элементfoo
, сделайтеfoo.getBarList()
иbarList
повторите это снова)map()
: взять поток, сделать что-то для каждого элемента, собрать единственный результат каждого процесса, вывести другой поток. Определение «сделать что-то функция» неявно. Если обработка какого-либо элемента приводит кnull
,null
используется для создания окончательного потока. Итак, количество элементов в результирующем потоке будет равно номеру входного потока.flatmap()
: взять поток элементов / потоков и функцию (явное определение), применить функцию к каждому элементу каждого потока и собрать весь промежуточный результирующий поток, чтобы получить больший поток («выравнивание»). Если обработка какого-либо элемента приводит к томуnull
, что пустой поток передается на последний этап «выравнивания». Количество элементов в результирующем потоке является суммой всех участвующих элементов во всех входных данных, если на входе находится несколько потоков.источник