No Java 8, qual é a diferença entre Stream.map()
e Stream.flatMap()
métodos?
java
java-8
java-stream
cassiomolin
fonte
fonte
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
's mapeador lambda retornaR
, umflatMap
' s mapeador lambda retorna umStream
deR
(Stream<R>
). Os fluxos retornados peloflatMap
mapeador do são efetivamente concatenados. Caso contrário, ambosmap
eflatMap
returnStream<R>
; a diferença é que os lambdas mapeador voltar,R
vs.Stream<R>
.Respostas:
Ambos
map
eflatMap
podem ser aplicados aStream<T>
e ambos retornam aStream<R>
. A diferença é que amap
operação produz um valor de saída para cada valor de entrada, enquanto aflatMap
operação produz um número arbitrário (zero ou mais) para cada valor de entrada.Isso se reflete nos argumentos de cada operação.
A
map
operação utiliza aFunction
, que é chamada para cada valor no fluxo de entrada e produz um valor de resultado, que é enviado ao fluxo de saída.A
flatMap
operação assume uma função que conceitualmente deseja consumir um valor e produzir um número arbitrário de valores. No entanto, em Java, é complicado para um método retornar um número arbitrário de valores, pois os métodos podem retornar apenas zero ou um valor. Poder-se-ia imaginar uma API na qual a função mapeadorflatMap
obtém um valor e retorna uma matriz ou umList
de valores, que são então enviados para a saída. Dado que essa é a biblioteca de fluxos, uma maneira particularmente adequada de representar um número arbitrário de valores de retorno é que a própria função do mapeador retorne um fluxo! Os valores do fluxo retornado pelo mapeador são drenados do fluxo e são passados para o fluxo de saída. Os "agrupamentos" de valores retornados por cada chamada para a função mapeador não são distinguidos no fluxo de saída, portanto, diz-se que a saída foi "nivelada".O uso típico é que a função mapeador
flatMap
retorneStream.empty()
se desejar enviar valores zero ou algo comoStream.of(a, b, c)
se desejar retornar vários valores. Mas é claro que qualquer fluxo pode ser retornado.fonte
flatMap
operação é exatamente o oposto do plano. Mais uma vez, deixe que os cientistas da computação mudem um termo. Como uma função sendo "transparente", significa que você não pode ver nada do que faz, apenas os resultados, enquanto diz coloquialmente que deseja que um processo seja transparente significa que deseja que cada parte dele seja vista.Stream.flatMap
, como pode ser adivinhado por seu nome, é a combinação de amap
e umaflat
operação. Isso significa que você primeiro aplica uma função aos seus elementos e depois a achata.Stream.map
aplica apenas uma função ao fluxo sem nivelar o fluxo.Para entender em que consiste o nivelamento de um fluxo, considere uma estrutura como a
[ [1,2,3],[4,5,6],[7,8,9] ]
que possui "dois níveis". Achatamento este meio transformando-o em uma estrutura de "um nível":[ 1,2,3,4,5,6,7,8,9 ]
.fonte
Eu gostaria de dar 2 exemplos para obter um ponto de vista mais prático:
Primeiro exemplo fazendo uso do mapa:
Nada de especial no primeiro exemplo, a
Function
é aplicado para retornarString
maiúsculas.Segundo exemplo fazendo uso de
flatMap
:No segundo exemplo, um fluxo de lista é passado. NÃO é um fluxo de número inteiro!
Se uma Função de transformação precisar ser usada (através do mapa), primeiro o Fluxo deverá ser achatado para outra coisa (um Fluxo de Inteiro).
Se o flatMap for removido, o seguinte erro será retornado: O operador + é indefinido para o (s) tipo (s) de argumento List, int.
NÃO é possível aplicar + 1 em uma lista de números inteiros!
fonte
Stream<Integer>
e não um fluxo deInteger
.Consulte a postagem totalmente para ter uma ideia clara,
map vs flatMap:
Para retornar um comprimento de cada palavra de uma lista, faríamos algo como abaixo.
Versão curta dada abaixo
Quando coletamos duas listas, dadas abaixo
Sem mapa plano => [1,2], [1,1] => [[1,2], [1,1]] Aqui duas listas são colocadas dentro de uma lista, portanto a saída será uma lista contendo listas
Com mapa plano => [1,2], [1,1] => [1,2,1,1] Aqui duas listas são achatadas e apenas os valores são colocados na lista; portanto, a saída será uma lista contendo apenas elementos
Basicamente, mescla todos os objetos em um
## Versão detalhada foi dada abaixo: -
Por exemplo: -
Considere uma lista ["STACK", "OOOVVVER"] e estamos tentando retornar uma lista como ["STACKOVER"] (retornando apenas letras exclusivas dessa lista). Inicialmente, faríamos algo como abaixo para retornar um lista ["EMPILHAMENTO"] de ["EMPILHAMENTO", "OOOVVVER"]
Aqui está o problema: o Lambda passado para o método map retorna uma matriz String para cada palavra. Portanto, o fluxo retornado pelo método map é realmente do tipo Stream, mas o que precisamos é de Stream para representar um fluxo de caracteres, abaixo a imagem ilustra o problema.
Figura A:
Você pode pensar que, podemos resolver esse problema usando o flatmap,
OK, vamos ver como resolver isso usando map e Arrays.stream Antes de tudo, você precisará de um fluxo de caracteres em vez de um fluxo de matrizes. Existe um método chamado Arrays.stream () que pegaria uma matriz e produziria um fluxo, por exemplo:
O exemplo acima ainda não funciona, porque agora terminamos com uma lista de fluxos (mais precisamente, Fluxo>). Em vez disso, devemos primeiro converter cada palavra em uma matriz de letras individuais e depois transformar cada matriz em um fluxo separado.
Usando o flatMap, poderemos corrigir esse problema da seguinte maneira:
O flatMap executaria o mapeamento de cada matriz não com fluxo, mas com o conteúdo desse fluxo. Todos os fluxos individuais que seriam gerados ao usar o mapa (Arrays :: stream) são mesclados em um único fluxo. A Figura B ilustra o efeito do uso do método flatMap. Compare-o com o que o mapa faz na figura A. Figura B
O método flatMap permite substituir cada valor de um fluxo por outro fluxo e unir todos os fluxos gerados em um único fluxo.
fonte
Resposta em uma linha:
flatMap
ajuda a achatar aCollection<Collection<T>>
em aCollection<T>
. Da mesma forma, ele também vai achatar umOptional<Optional<T>>
emOptional<T>
.Como você pode ver,
map()
apenas:Stream<List<Item>>
List<List<Item>>
e com
flatMap()
:Stream<Item>
List<Item>
Este é o resultado do teste do código usado logo abaixo:
Código usado :
fonte
A função para a qual você passa
stream.map
tem que retornar um objeto. Isso significa que cada objeto no fluxo de entrada resulta em exatamente um objeto no fluxo de saída.A função que você passa
stream.flatMap
retorna um fluxo para cada objeto. Isso significa que a função pode retornar qualquer número de objetos para cada objeto de entrada (incluindo nenhum). Os fluxos resultantes são então concatenados para um fluxo de saída.fonte
Department
s em sua organização. Cada departamento tem entre 0 e nEmployee
s. O que você precisa é de um fluxo de todos os funcionários. Então, o que você faz? Você escreve um método flatMap que pega um departamento e retorna um fluxo de seus funcionários.flatMap
? Suspeito que possa ser acidental e não ilustra o caso de uso principal ou o motivo pelo qualflatMap
existe. (Continua abaixo ...)flatMap
é acomodar erros que estariam presentes ao usarmap
. Como você lida com casos em que um ou mais itens no conjunto original não podem ser mapeados para um item de saída? Ao introduzir um conjunto intermediário (digamos umOptional
ouStream
) para cada objeto de entrada,flatMap
você pode excluir os objetos de entrada "inválidos" (ou as chamadas "maçãs ruins", no espírito de stackoverflow.com/a/52248643/107158 ) do conjunto final.para um mapa, temos uma lista de elementos e a (função, ação) f assim:
e para o mapa plano, temos uma lista de elementos e temos uma (função, ação) f e queremos que o resultado seja nivelado:
fonte
Sinto que a maioria das respostas aqui complica o problema simples. Se você já entende como os
map
trabalhos devem ser razoavelmente fáceis de entender.Há casos em que podemos terminar com estruturas aninhadas indesejadas ao usar
map()
, oflatMap()
método é projetado para superar isso, evitando o empacotamento.Exemplos:
1
Podemos evitar listas aninhadas usando
flatMap
:2
Onde:
fonte
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());
. É deve serStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
O artigo da Oracle sobre Opcional destaca essa diferença entre mapa e flatmap:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
fonte
Não tenho muita certeza de que devo responder isso, mas toda vez que encontro alguém que não entende isso, uso o mesmo exemplo.
Imagine que você tem uma maçã. A
map
está transformando essa maçã em,apple-juice
por exemplo, ou em um mapeamento um a um .Pegue a mesma maçã e tire apenas as sementes, é isso que
flatMap
faz, ou uma para muitas , uma maçã como entrada, muitas sementes como saída.fonte
flatMap
caso, você primeiro coleta as sementes de cada maçã em sacos separados, um saco por maçã, antes de despejar todos os sacos em um único saco?flatmap
não era realmente preguiçoso, mas desde java-10 é preguiçosoflatMap + lazy
, aposto que haverá algumas respostas.map () e flatMap ()
map()
Apenas pega uma Function como um parâmetro lambda onde T é o elemento e R o elemento de retorno criado usando T. No final, teremos um Stream com objetos do tipo R. Um exemplo simples pode ser:
Ele simplesmente pega os elementos 1 a 5 do Type
Integer
, usa cada elemento para criar um novo elemento do tipoString
com valor"prefix_"+integer_value
e o imprime.flatMap()
É útil saber que flatMap () assume uma função
F<T, R>
em queT é um tipo do qual um Stream pode ser construído a partir de / com . Pode ser uma lista (T.stream ()), uma matriz (Arrays.stream (someArray)), etc. qualquer coisa a partir da qual um fluxo possa ser com / ou formulário. no exemplo abaixo, cada desenvolvedor tem muitos idiomas, portanto, desenvolvedor. Idiomas é uma lista e usará um parâmetro lambda.
R é o fluxo resultante que será construído usando T. Sabendo que temos muitas instâncias de T, naturalmente teremos muitos fluxos de R. Todos esses fluxos do tipo R agora serão combinados em um único fluxo 'plano' do tipo R .
Exemplo
Os exemplos de Bachiri Taoufiq vêem sua resposta aqui são simples e fáceis de entender. Apenas para maior clareza, digamos que temos uma equipe de desenvolvedores:
, com cada desenvolvedor conhecendo vários idiomas:
Aplicando Stream.map () no dev_team para obter os idiomas de cada dev:
lhe dará essa estrutura:
que é basicamente a
List<List<Languages>> /Object[Languages[]]
. Não é tão bonito, nem Java8!com
Stream.flatMap()
você pode 'achatar' as coisas, uma vez que pega a estrutura acimae a transforma
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, que pode ser usada basicamente comoList<Languages>/Language[]/etc
...portanto, no final, seu código faria mais sentido assim:
ou simplesmente:
Quando usar map () e flatMap () :
Use
map()
quando cada elemento do tipo T do seu fluxo deve ser mapeado / transformado em um único elemento do tipo R. O resultado é um mapeamento do tipo (1 elemento inicial -> 1 elemento final) e o novo fluxo de elementos do tipo R é retornado.Use
flatMap()
quando cada elemento do tipo T do seu fluxo deve ser mapeado / transformado em Coleções de elementos do tipo R. O resultado é um mapeamento do tipo (1 elemento inicial -> n elementos finais) . Essas coleções são mescladas (ou niveladas ) com um novo fluxo de elementos do tipo R. Isso é útil, por exemplo, para representar loops aninhados .Antes do Java 8:
Pós Java 8
fonte
Mapa: - Este método utiliza uma função como argumento e retorna um novo fluxo que consiste nos resultados gerados aplicando a função passada a todos os elementos do fluxo.
Vamos imaginar, eu tenho uma lista de valores inteiros (1,2,3,4,5) e uma interface de função cuja lógica é quadrada do número inteiro passado. (e -> e * e).
resultado:-
Como você pode ver, uma saída é um novo fluxo cujos valores são quadrados dos valores do fluxo de entrada.
http://codedestine.com/java-8-stream-map-method/
FlatMap: - Este método utiliza uma Função como argumento, essa função aceita um parâmetro T como argumento de entrada e retorna um fluxo do parâmetro R como valor de retorno. Quando essa função é aplicada a cada elemento desse fluxo, ela produz um fluxo de novos valores. Todos os elementos desses novos fluxos gerados por cada elemento são copiados para um novo fluxo, que será um valor de retorno desse método.
Vamos imaginar, eu tenho uma lista de objetos dos alunos, onde cada aluno pode optar por vários assuntos.
resultado:-
Como você pode ver, uma saída é um novo fluxo cujos valores são uma coleção de todos os elementos dos fluxos retornados por cada elemento do fluxo de entrada.
[S1, S2, S3] -> [{"história", "matemática", "geografia"}, {"economia", "biologia"}, {"ciência", "matemática"}] -> faça matérias exclusivas - > [economia, biologia, geografia, ciência, história, matemática]
http://codedestine.com/java-8-stream-flatmap-method/
fonte
.map é para mapeamento A -> B
converte qualquer item
A
em qualquer itemB
. Javadoc.flatMap é para A -> Stream <B> concatenando
- 1 converte qualquer item
A
emStream< B>
, e - 2 concatena todos os fluxos em um fluxo (plano). JavadocNota 1: Embora o último exemplo seja plano para um fluxo de primitivas (IntStream) em vez de um fluxo de objetos (Stream), ele ainda ilustra a idéia do
.flatMap
.Nota 2: Apesar do nome, o método String.chars () retorna ints. Portanto, a coleção real será:,
[100, 111, 103, 99, 97, 116]
onde100
está o código de'd'
,111
é o código de'o'
etc. Novamente, para fins ilustrativos, é apresentado como [d, o, g, c, a, t].fonte
Resposta simples.
A
map
operação pode produzir umStream
deStream
.EXStream<Stream<Integer>>
flatMap
operação produzirá apenasStream
algo. EXStream<Integer>
fonte
Também pode haver boa analogia com o C #, se você estiver familiarizado. Basicamente, o C # é
Select
semelhante ao javamap
e c #SelectMany
javaflatMap
. O mesmo se aplica ao Kotlin para coleções.fonte
Isso é muito confuso para iniciantes. A diferença básica é
map
emitir um item para cada entrada na lista eflatMap
é basicamente uma operaçãomap
+flatten
. Para ser mais claro, use flatMap quando precisar de mais de um valor, por exemplo, quando você espera que um loop retorne matrizes, o flatMap será realmente útil nesse caso.Eu escrevi um blog sobre isso, você pode conferir aqui .
fonte
Transmita operações
flatMap
emap
aceite uma função como entrada.flatMap
espera que a função retorne um novo fluxo para cada elemento do fluxo e retorne um fluxo que combine todos os elementos dos fluxos retornados pela função para cada elemento. Em outras palavras, comflatMap
, para cada elemento da fonte, vários elementos serão criados pela função. http://www.zoftino.com/java-stream-examples#flatmap-operationmap
espera que a função retorne um valor transformado e retorne um novo fluxo contendo os elementos transformados. Em outras palavras, commap
, para cada elemento da fonte, um elemento transformado será criado pela função. http://www.zoftino.com/java-stream-examples#map-operationfonte
flatMap()
também aproveita a avaliação preguiçosa parcial dos fluxos. Ele lerá o fluxo inicial e somente quando necessário, irá para o próximo fluxo. O comportamento é explicado em detalhes aqui: O flatMap é garantido como preguiçoso?fonte
Se você pensa
map()
como uma iteração (for
loop de um nível ),flatmap()
é uma iteração de dois níveis (como umfor
loop aninhado ). (Insira cada elemento iteradofoo
e façafoo.getBarList()
e iterebarList
novamente)map()
: pegue um fluxo, faça algo com cada elemento, colete o resultado único de cada processo, produza outro fluxo. A definição de "fazer alguma coisa funcionar" está implícita. Se o processamento de qualquer elemento resultar emnull
,null
é usado para compor o fluxo final. Portanto, o número de elementos no fluxo resultante será igual ao número do fluxo de entrada.flatmap()
: pegue um fluxo de elementos / fluxos e uma função (definição explícita), aplique a função a cada elemento de cada fluxo e colete todo o fluxo resultante intermediário para ser um fluxo maior ("nivelamento"). Se o processamento de qualquer elemento resultarnull
, o fluxo vazio será fornecido na etapa final do "achatamento". O número de elementos no fluxo resultante é o total de todos os elementos participantes em todas as entradas, se a entrada for de vários fluxos.fonte