Qual é a diferença entre os métodos map () e flatMap () no Java 8?


706

No Java 8, qual é a diferença entre Stream.map()e Stream.flatMap()métodos?


55
O tipo de assinatura conta a história toda. map :: Stream T -> (T -> R) -> Stream R, flatMap :: Stream T -> (T -> Stream R) -> Stream R.
31814 Chris Martin

98
fwiw, essas assinaturas de tipo nem se parecem com Java. (Eu sei, eu sei - mas dizer que diz "toda a história" WRT mapear / flatMap assume um monte de conhecimento sobre o novo e melhorado "Java ++")
michael

16
@ Michael Esse tipo de assinatura se parece com Haskell, não Java. Mas não está claro se a assinatura Java real é mais legível: <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper).
Stuart Marcas

8
Ah, sim, eu estava me referindo ao "Java real". Como o C ++, o Java moderno é quase irreconhecível para quem começou a usá-lo nos anos 90 (como eu fiz nas duas linguagens). Apenas respondendo ao comentário, as assinaturas desse método dificilmente contam uma "história completa", pelo menos não mais, não sem exposição adicional (ou nesse caso, tradução).
22617 Michael

2
O que quer dizer, um map's mapeador lambda retorna R, um flatMap' s mapeador lambda retorna um Streamde R( Stream<R>). Os fluxos retornados pelo flatMapmapeador do são efetivamente concatenados. Caso contrário, ambos mape flatMapreturn Stream<R>; a diferença é que os lambdas mapeador voltar, Rvs. Stream<R>.
Derekm 07/0318

Respostas:


816

Ambos mape flatMappodem ser aplicados a Stream<T>e ambos retornam a Stream<R>. A diferença é que a mapoperação produz um valor de saída para cada valor de entrada, enquanto a flatMapoperaçã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 mapoperação utiliza a Function, que é chamada para cada valor no fluxo de entrada e produz um valor de resultado, que é enviado ao fluxo de saída.

A flatMapoperaçã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 mapeador flatMapobtém um valor e retorna uma matriz ou umListde 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 flatMapretorne Stream.empty()se desejar enviar valores zero ou algo como Stream.of(a, b, c)se desejar retornar vários valores. Mas é claro que qualquer fluxo pode ser retornado.


26
Parece-me que a flatMapoperaçã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.
Coladict

45
@coladict Tente visualizá-lo de uma perspectiva diferente: não é um caso transparente em que você pode ver o funcionamento interno, mas toda a função em si é transparente, ou seja, invisível para você - enquanto continua fazendo o trabalho e permitindo que você veja o que você ' estou trabalhando com. Nesse caso, "flat" refere-se ao oposto de "aninhado", o flatmap remove um nível de aninhamento nivelando.
Zefiro

7
@coladict A coisa "transparente" come minha cabeça há anos. Fico feliz em saber que pelo menos uma outra pessoa se sente da mesma maneira.
Ashok Bijoy Debnath

9
Achatamento vem de transformar a estrutura de nível 2 na estrutura de nível único, ver a resposta de Dici para um exemplo stackoverflow.com/a/26684582/6012102
andrzej.szmukala

26
Esta é a melhor explicação para o flatMap . É isso que faz com que tudo seja clicado: Os valores do fluxo retornado pelo mapeador são drenados do fluxo e 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" . Obrigado!
neevek

464

Stream.flatMap, como pode ser adivinhado por seu nome, é a combinação de a mape uma flatoperação. Isso significa que você primeiro aplica uma função aos seus elementos e depois a achata. Stream.mapaplica 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 ].


5
simples e doce
bluelurker

3
Haha, para ser justo, ainda estou surpreso ao ver quanto tráfego essa pergunta recebe. Outra observação engraçada é que já faz quase cinco anos que escrevi essa resposta e houve um padrão bastante consistente de votação, em que a resposta aceita recebe aproximadamente dois votos positivos para cada uma das respostas recebidas. É surpreendentemente consistente.
Dici 24/08/19

1
como é que isto não é a resposta aceita, obrigado para ir direto ao ponto e colocar um exemplo muito simples
1mike12

233

Eu gostaria de dar 2 exemplos para obter um ponto de vista mais prático:
Primeiro exemplo fazendo uso do mapa:

@Test
public void convertStringToUpperCaseStreams() {
    List<String> collected = Stream.of("a", "b", "hello") // Stream of String 
            .map(String::toUpperCase) // Returns a stream consisting of the results of applying the given function to the elements of this stream.
            .collect(Collectors.toList());
    assertEquals(asList("A", "B", "HELLO"), collected);
}   

Nada de especial no primeiro exemplo, a Functioné aplicado para retornar Stringmaiúsculas.

Segundo exemplo fazendo uso de flatMap:

@Test
public void testflatMap() throws Exception {
    List<Integer> together = Stream.of(asList(1, 2), asList(3, 4)) // Stream of List<Integer>
            .flatMap(List::stream)
            .map(integer -> integer + 1)
            .collect(Collectors.toList());
    assertEquals(asList(2, 3, 4, 5), together);
}

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!


@PrashanthDebbadwar Acho que você acabaria com um fluxo de Stream<Integer>e não um fluxo de Integer.
Payne

166

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"]

public class WordMap {
  public static void main(String[] args) {
    List<String> lst = Arrays.asList("STACK","OOOVER");
    lst.stream().map(w->w.split("")).distinct().collect(Collectors.toList());
  }
}

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:

insira a descrição da imagem aqui

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:

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
    .map(Arrays::stream).distinct() //Make array in to separate stream
    .collect(Collectors.toList());

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:

String[] arrayOfWords = {"STACK", "OOOVVVER"};
Stream<String> streamOfWords = Arrays.stream(arrayOfWords);
streamOfWords.map(s->s.split("")) //Converting word in to array of letters
    .flatMap(Arrays::stream).distinct() //flattens each generated stream in to a single stream
    .collect(Collectors.toList());

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 insira a descrição da imagem aqui

O método flatMap permite substituir cada valor de um fluxo por outro fluxo e unir todos os fluxos gerados em um único fluxo.


2
Boa explicação diagramática.
Hitesh

108

Resposta em uma linha: flatMapajuda a achatar a Collection<Collection<T>>em aCollection<T> . Da mesma forma, ele também vai achatar um Optional<Optional<T>>em Optional<T>.

insira a descrição da imagem aqui

Como você pode ver, map()apenas:

  • O tipo intermediário é Stream<List<Item>>
  • O tipo de retorno é List<List<Item>>

e com flatMap():

  • O tipo intermediário é Stream<Item>
  • O tipo de retorno é List<Item>

Este é o resultado do teste do código usado logo abaixo:

-------- Without flatMap() -------------------------------
     collect() returns: [[Laptop, Phone], [Mouse, Keyboard]]

-------- With flatMap() ----------------------------------
     collect() returns: [Laptop, Phone, Mouse, Keyboard]

Código usado :

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class Parcel {
  String name;
  List<String> items;

  public Parcel(String name, String... items) {
    this.name = name;
    this.items = Arrays.asList(items);
  }

  public List<String> getItems() {
    return items;
  }

  public static void main(String[] args) {
    Parcel amazon = new Parcel("amazon", "Laptop", "Phone");
    Parcel ebay = new Parcel("ebay", "Mouse", "Keyboard");
    List<Parcel> parcels = Arrays.asList(amazon, ebay);

    System.out.println("-------- Without flatMap() ---------------------------");
    List<List<String>> mapReturn = parcels.stream()
      .map(Parcel::getItems)
      .collect(Collectors.toList());
    System.out.println("\t collect() returns: " + mapReturn);

    System.out.println("\n-------- With flatMap() ------------------------------");
    List<String> flatMapReturn = parcels.stream()
      .map(Parcel::getItems)
      .flatMap(Collection::stream)
      .collect(Collectors.toList());
    System.out.println("\t collect() returns: " + flatMapReturn);
  }
}

8
Exemplo muito nítidas .., não iria demorar mais do que alguns segundos para entender o conceito com o seu exemplo ...
TechDog

2
boa explicação. realmente aprecio a explicação simples e melhor
Sachin Rane

42

A função para a qual você passa stream.maptem 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.flatMapretorna 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.


Por que você deseja "retornar qualquer número de objetos para cada objeto de entrada (incluindo nenhum)"?
Derek Mahar 12/12

4
@DerekMahar Haveria muitos casos de uso para isso. Por exemplo, digamos que você tenha um fluxo de Departments em sua organização. Cada departamento tem entre 0 e n Employees. 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.
Philipp

Philipp, seu exemplo ilustra o principal motivo de uso flatMap? Suspeito que possa ser acidental e não ilustra o caso de uso principal ou o motivo pelo qual flatMapexiste. (Continua abaixo ...)
Derek Mahar 12/12

Depois de ler dzone.com/articles/understanding-flatmap , acho que a principal motivação por trás disso flatMapé acomodar erros que estariam presentes ao usar map. 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 um Optionalou Stream) para cada objeto de entrada, flatMapvocê 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.
Derek Mahar 12/12

1
@DerekMahar Sim, as estatísticas em que cada objeto de entrada pode ou não retornar um objeto de saída são outro bom caso de uso para o mapa plano.
Philipp

29

para um mapa, temos uma lista de elementos e a (função, ação) f assim:

[a,b,c] f(x) => [f(a),f(b),f(c)]

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:

[[a,b],[c,d,e]] f(x) =>[f(a),f(b),f(c),f(d),f(e)]

25

Sinto que a maioria das respostas aqui complica o problema simples. Se você já entende como os maptrabalhos devem ser razoavelmente fáceis de entender.

Há casos em que podemos terminar com estruturas aninhadas indesejadas ao usar map(), o flatMap()método é projetado para superar isso, evitando o empacotamento.


Exemplos:

1

List<List<Integer>> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .collect(Collectors.toList());

Podemos evitar listas aninhadas usando flatMap:

List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3))
  .flatMap(i -> i.stream())
  .collect(Collectors.toList());

2

Optional<Optional<String>> result = Optional.of(42)
      .map(id -> findById(id));

Optional<String> result = Optional.of(42)
      .flatMap(id -> findById(id));

Onde:

private Optional<String> findById(Integer id)

desculpe, mas o segundo snippet do ponto 1 não está compilando em vez de 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());
arthur

@arthur Eu acho que eu usei Stream e A Lista de Vavr aqui - mas eu concordo que pode ser confuso um pouco - Eu vou mudar isso para Java padrão
Grzegorz Piwowarek


22

O artigo da Oracle sobre Opcional destaca essa diferença entre mapa e flatmap:

String version = computer.map(Computer::getSoundcard)
                  .map(Soundcard::getUSB)
                  .map(USB::getVersion)
                  .orElse("UNKNOWN");

Infelizmente, esse código não é compilado. Por quê? O computador variável é do tipo Optional<Computer>, portanto, é perfeitamente correto chamar o método map. No entanto, getSoundcard () retorna um objeto do tipo Opcional. Isso significa que o resultado da operação do mapa é um objeto do tipo Optional<Optional<Soundcard>>. Como resultado, a chamada para getUSB () é inválida porque o Opcional mais externo contém como valor outro Opcional, o que obviamente não suporta o método getUSB ().

Com fluxos, o método flatMap assume uma função como argumento, que retorna outro fluxo. Essa função é aplicada a cada elemento de um fluxo, o que resultaria em um fluxo de fluxos. No entanto, o flatMap tem o efeito de substituir cada fluxo gerado pelo conteúdo desse fluxo. Em outras palavras, todos os fluxos separados gerados pela função são agrupados ou "achatados" em um único fluxo. O que queremos aqui é algo semelhante, mas queremos "achatar" um opcional de dois níveis em um .

Opcional também suporta um método flatMap. Seu objetivo é aplicar a função de transformação no valor de um Opcional (exatamente como a operação de mapa faz) e depois achatar o Opcional de dois níveis resultante em um único .

Portanto, para corrigir nosso código, precisamos reescrevê-lo da seguinte forma usando flatMap:

String version = computer.flatMap(Computer::getSoundcard)
                   .flatMap(Soundcard::getUSB)
                   .map(USB::getVersion)
                   .orElse("UNKNOWN");

O primeiro flatMap garante que um Optional<Soundcard>é retornado em vez de um Optional<Optional<Soundcard>>, e o segundo flatMap alcança o mesmo objetivo de retornar um Optional<USB>. Observe que a terceira chamada apenas precisa ser um map () porque getVersion () retorna uma String em vez de um objeto Opcional.

http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html


1
A pergunta era sobre Stream.map e Stream.flatMap e não sobre Optional.map anfd Optional.flatMap
djames

4
Mas isso me ajudou muito a entender meus problemas com o opcional e o flatmap, muito obrigado!
Loïc

2
@djames, é uma resposta perfeitamente válida, lê-lo a partir de parágrafo "Com correntes, o método flatMap leva uma função como um argumento ..." :)
skwisgaar

Penso que este é um complemento muito útil para algumas das outras respostas aqui.
Mz A

A versão flatMap () também gera nullpointerexception se soundCard for nulo. Então, onde está o benefício prometido do Opcional?
Ekaterina

16

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 mapestá transformando essa maçã em, apple-juicepor exemplo, ou em um mapeamento um a um .

Pegue a mesma maçã e tire apenas as sementes, é isso que flatMapfaz, ou uma para muitas , uma maçã como entrada, muitas sementes como saída.


4
Isso é um exemplo interessante :)
cassiomolin

Para o flatMapcaso, 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?
Derek Mahar

@DerekMahar que costumava ser um pobre em um único saco antes de java-10, o significado flatmapnão era realmente preguiçoso, mas desde java-10 é preguiçoso
Eugene

@Eugene, por favor, explique um conceito um pouco mais preguiçoso, o qual você está tentando explicar não está claro para mim.
JAVA

@JAVA basta pesquisar flatMap + lazy, aposto que haverá algumas respostas.
Eugene

16

map () e flatMap ()

  1. 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:

Stream
  .of(1,2,3,4,5)
  .map(myInt -> "preFix_"+myInt)
  .forEach(System.out::println);

Ele simplesmente pega os elementos 1 a 5 do Type Integer, usa cada elemento para criar um novo elemento do tipo Stringcom valor "prefix_"+integer_valuee o imprime.

  1. flatMap()

É útil saber que flatMap () assume uma função F<T, R>em que

  • T é 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:

dev_team = {dev_1,dev_2,dev_3}

, com cada desenvolvedor conhecendo vários idiomas:

dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_2 = {lang_e,lang_f}

Aplicando Stream.map () no dev_team para obter os idiomas de cada dev:

dev_team.map(dev -> dev.getLanguages())

lhe dará essa estrutura:

{ 
  {lang_a,lang_b,lang_c},
  {lang_d},
  {lang_e,lang_f}
}

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 acima
e a transforma {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}, que pode ser usada basicamente como List<Languages>/Language[]/etc...

portanto, no final, seu código faria mais sentido assim:

dev_team
   .stream()    /* {dev_1,dev_2,dev_3} */
   .map(dev -> dev.getLanguages()) /* {{lang_a,...,lang_c},{lang_d}{lang_e,lang_f}}} */
   .flatMap(languages ->  languages.stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
   .doWhateverWithYourNewStreamHere();

ou simplesmente:

dev_team
       .stream()    /* {dev_1,dev_2,dev_3} */
       .flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
       .doWhateverWithYourNewStreamHere();

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:

List<Foo> myFoos = new ArrayList<Foo>();
    for(Foo foo: myFoos){
        for(Bar bar:  foo.getMyBars()){
            System.out.println(bar.getMyName());
        }
    }

Pós Java 8

myFoos
    .stream()
    .flatMap(foo -> foo.getMyBars().stream())
    .forEach(bar -> System.out.println(bar.getMyName()));

11

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).

List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> newList = intList.stream().map( e -> e * e ).collect(Collectors.toList());

System.out.println(newList);

resultado:-

[1, 4, 9, 16, 25]

Como você pode ver, uma saída é um novo fluxo cujos valores são quadrados dos valores do fluxo de entrada.

[1, 2, 3, 4, 5] -> apply e -> e * e -> [ 1*1, 2*2, 3*3, 4*4, 5*5 ] -> [1, 4, 9, 16, 25 ]

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.

List<Student> studentList = new ArrayList<Student>();

  studentList.add(new Student("Robert","5st grade", Arrays.asList(new String[]{"history","math","geography"})));
  studentList.add(new Student("Martin","8st grade", Arrays.asList(new String[]{"economics","biology"})));
  studentList.add(new Student("Robert","9st grade", Arrays.asList(new String[]{"science","math"})));

  Set<Student> courses = studentList.stream().flatMap( e -> e.getCourse().stream()).collect(Collectors.toSet());

  System.out.println(courses);

resultado:-

[economics, biology, geography, science, history, math]

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/


pode fazer a diferença se você fornecer o código em vez de apenas provinding ligação doc
Charles-Antoine Fournel

11

.map é para mapeamento A -> B

Stream.of("dog", "cat")              // stream of 2 Strings
    .map(s -> s.length())            // stream of 2 Integers: [3, 3]

converte qualquer item Aem qualquer item B. Javadoc


.flatMap é para A -> Stream <B> concatenando

Stream.of("dog", "cat")             // stream of 2 Strings
    .flatMapToInt(s -> s.chars())   // stream of 6 ints:      [d, o, g, c, a, t]

- 1 converte qualquer item Aem Stream< B>, e - 2 concatena todos os fluxos em um fluxo (plano). Javadoc


Nota 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] onde 100está o código de 'd', 111é o código de 'o'etc. Novamente, para fins ilustrativos, é apresentado como [d, o, g, c, a, t].


3
Melhor resposta. Direto ao ponto com exemplos
GabrielBB 27/03

1

Resposta simples.

A mapoperação pode produzir um Streamde Stream.EXStream<Stream<Integer>>

flatMapoperação produzirá apenas Streamalgo. EXStream<Integer>


0

Também pode haver boa analogia com o C #, se você estiver familiarizado. Basicamente, o C # é Selectsemelhante ao java mape c # SelectManyjava flatMap. O mesmo se aplica ao Kotlin para coleções.


0

Isso é muito confuso para iniciantes. A diferença básica é mapemitir um item para cada entrada na lista e flatMapé basicamente uma operação map+ 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 .



0

Transmita operações flatMape mapaceite uma função como entrada.

flatMapespera 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, com flatMap, para cada elemento da fonte, vários elementos serão criados pela função. http://www.zoftino.com/java-stream-examples#flatmap-operation

mapespera que a função retorne um valor transformado e retorne um novo fluxo contendo os elementos transformados. Em outras palavras, com map, para cada elemento da fonte, um elemento transformado será criado pela função. http://www.zoftino.com/java-stream-examples#map-operation


0

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?


0

Se você pensa map()como uma iteração ( forloop de um nível ), flatmap()é uma iteração de dois níveis (como um forloop aninhado ). (Insira cada elemento iterado fooe faça foo.getBarList()e itere barListnovamente)


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 em null, 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 resultar null, 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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.