En Java 8, ¿cuál es la diferencia entre Stream.map()
y los Stream.flatMap()
métodos?
java
java-8
java-stream
cassiomolin
fuente
fuente
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
el mapeador lambda de a regresaR
,flatMap
el mapeador lambda de a regresa unStream
deR
(Stream<R>
). Las secuencias devueltas por elflatMap
mapeador de 's se concatenan efectivamente. De lo contrario, ambosmap
yflatMap
volverStream<R>
; la diferencia es lo que devuelven los lambdas asignador,R
vsStream<R>
.Respuestas:
Ambos
map
yflatMap
se pueden aplicar a aStream<T>
y ambos devuelven aStream<R>
. La diferencia es que lamap
operación produce un valor de salida para cada valor de entrada, mientras que laflatMap
operación produce un número arbitrario (cero o más) valores para cada valor de entrada.Esto se refleja en los argumentos de cada operación.
La
map
operación toma unFunction
, que se llama para cada valor en la secuencia de entrada y produce un valor de resultado, que se envía a la secuencia de salida.La
flatMap
operación toma una función que conceptualmente quiere consumir un valor y producir un número arbitrario de valores. Sin embargo, en Java, es engorroso que un método devuelva un número arbitrario de valores, ya que los métodos solo pueden devolver un valor cero o uno. Uno podría imaginar una API donde la función del mapeadorflatMap
toma un valor y devuelve una matriz o unList
de valores, que luego se envían a la salida. Dado que esta es la biblioteca de secuencias, una forma particularmente adecuada de representar un número arbitrario de valores de retorno es que la función del mapeador en sí misma devuelva una secuencia. Los valores de la secuencia devueltos por el asignador se drenan de la secuencia y se pasan a la secuencia de salida. Los "grupos" de valores devueltos por cada llamada a la función del mapeador no se distinguen en absoluto en el flujo de salida, por lo tanto, se dice que la salida se ha "aplanado".El uso típico es que la función de mapeador de
flatMap
devolverStream.empty()
si quiere enviar valores cero, o algo así comoStream.of(a, b, c)
si quiere devolver varios valores. Pero, por supuesto, cualquier flujo puede ser devuelto.fuente
flatMap
operación es exactamente lo contrario de plana. Una vez más, déjelo en manos de los informáticos para convertir un término en su cabeza. Al igual que una función que es "transparente", lo que significa que no puede ver nada de lo que hace, solo los resultados, mientras que coloquialmente dice que desea que un proceso sea transparente significa que quiere que se vean todas sus partes.Stream.flatMap
, como se puede adivinar por su nombre, es la combinación de aymap
unaflat
operación. Eso significa que primero aplica una función a sus elementos y luego la aplana.Stream.map
solo aplica una función a la secuencia sin aplanarla.Para comprender en qué consiste el aplanamiento de una secuencia, considere una estructura como la
[ [1,2,3],[4,5,6],[7,8,9] ]
que tiene "dos niveles". El aplanamiento de este medio transformándolo en una estructura de "un nivel":[ 1,2,3,4,5,6,7,8,9 ]
.fuente
Me gustaría dar 2 ejemplos para obtener un punto de vista más práctico:
Primer ejemplo haciendo uso del mapa:
Nada especial en el primer ejemplo,
Function
se aplica a para devolver laString
mayúscula.Segundo ejemplo haciendo uso de
flatMap
:En el segundo ejemplo, se pasa una secuencia de lista. ¡NO es un flujo de enteros!
Si se debe usar una Función de transformación (a través del mapa), primero se debe aplanar la Corriente a otra cosa (una Corriente de Entero).
Si se elimina flatMap, se devuelve el siguiente error: el operador + no está definido para la lista de tipos de argumento, int.
¡NO es posible aplicar + 1 en una Lista de enteros!
fuente
Stream<Integer>
lugar de un Stream deInteger
.Revisa la publicación por completo para tener una idea clara,
map vs flatMap:
Para devolver una longitud de cada palabra de una lista, haríamos algo como a continuación.
Versión corta dada a continuación
Cuando recopilamos dos listas, dadas a continuación
Sin mapa plano => [1,2], [1,1] => [[1,2], [1,1]] Aquí se colocan dos listas dentro de una lista, por lo que la salida será una lista que contiene listas
Con mapa plano => [1,2], [1,1] => [1,2,1,1] Aquí se aplanan dos listas y solo los valores se colocan en la lista, por lo que la salida será una lista que solo contiene elementos
Básicamente combina todos los objetos en uno
## La versión detallada se ha proporcionado a continuación: -
Por ejemplo: -
Considere una lista ["STACK", "OOOVVVER"] y estamos tratando de devolver una lista como ["STACKOVER"] (devolviendo solo letras únicas de esa lista) Inicialmente, haríamos algo como a continuación para devolver un lista ["STACKOVER"] de ["STACK", "OOOVVVER"]
Aquí el problema es que Lambda pasado al método de mapa devuelve una matriz de cadenas para cada palabra, por lo que la secuencia devuelta por el método de mapa es en realidad de tipo Stream, pero lo que necesitamos es Stream para representar una secuencia de caracteres, la imagen de abajo ilustra el problema.
Figura A
Puede pensar que, podemos resolver este problema usando un mapa plano,
OK, veamos cómo resolver esto usando map y Arrays.stream En primer lugar, necesitará una secuencia de caracteres en lugar de una secuencia de matrices. Hay un método llamado Arrays.stream () que tomaría una matriz y produciría una secuencia, por ejemplo:
Lo anterior aún no funciona, porque ahora terminamos con una lista de secuencias (más precisamente, Stream>). En su lugar, primero debemos convertir cada palabra en una matriz de letras individuales y luego hacer que cada matriz se convierta en una secuencia separada
Al usar flatMap deberíamos poder solucionar este problema de la siguiente manera:
flatMap realizaría el mapeo de cada matriz no con la secuencia sino con el contenido de esa secuencia. Todas las secuencias individuales que se generarían al usar el mapa (Arrays :: stream) se fusionan en una sola secuencia. La Figura B ilustra el efecto del uso del método flatMap. Compárelo con lo que hace el mapa en la figura A. Figura B
El método flatMap le permite reemplazar cada valor de una secuencia con otra secuencia y luego une todas las secuencias generadas en una sola secuencia.
fuente
Respuesta de una línea:
flatMap
ayuda a aplanar aCollection<Collection<T>>
en aCollection<T>
. De la misma manera, también aplanará unOptional<Optional<T>>
enOptional<T>
.Como puedes ver,
map()
solo con :Stream<List<Item>>
List<List<Item>>
y con
flatMap()
:Stream<Item>
List<Item>
Este es el resultado de la prueba del código utilizado a continuación:
Código usado :
fuente
La función a la que pasa
stream.map
tiene que devolver un objeto. Eso significa que cada objeto en la secuencia de entrada da como resultado exactamente un objeto en la secuencia de salida.La función a la que pasa
stream.flatMap
devuelve una secuencia para cada objeto. Eso significa que la función puede devolver cualquier número de objetos para cada objeto de entrada (incluido ninguno). Las secuencias resultantes se concatenan a una secuencia de salida.fuente
Department
s en su organización. Cada departamento tiene entre 0 y nEmployee
s. Lo que necesita es un flujo de todos los empleados. Entonces, ¿Qué haces? Escribe un método flatMap que toma un departamento y devuelve una secuencia de sus empleados.flatMap
? Sospecho que puede ser incidental y no ilustra el caso de uso clave o la razón por la cualflatMap
existe. (Continúa abajo ...)flatMap
es acomodar los errores que estarían presentes al usarlosmap
. ¿Cómo maneja los casos en que uno o más elementos del conjunto original no pueden asignarse a un elemento de salida? Al introducir un conjunto intermedio (digamos unOptional
oStream
) para cada objeto de entrada, leflatMap
permite excluir los objetos de entrada "no válidos" (o las llamadas "manzanas podridas" en el espíritu de stackoverflow.com/a/52248643/107158 ) del conjunto finalpara un mapa tenemos una lista de elementos y a (función, acción) f entonces:
y para el mapa plano tenemos una lista de elementos y tenemos una (función, acción) f y queremos que el resultado sea plano:
fuente
Tengo la sensación de que la mayoría de las respuestas aquí complican demasiado el simple problema. Si ya comprende cómo
map
funciona, eso debería ser bastante fácil de entender.Hay casos en los que podemos terminar con estructuras anidadas no deseadas cuando se usa
map()
, elflatMap()
método está diseñado para superar esto evitando el ajuste.Ejemplos:
1
Podemos evitar tener listas anidadas usando
flatMap
:2
dónde:
fuente
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());
. Debe serStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
El artículo de Oracle sobre Opcional destaca esta diferencia entre mapa y mapa plano:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
fuente
No estoy muy seguro de que deba responder esto, pero cada vez que me enfrento a alguien que no entiende esto, uso el mismo ejemplo.
Imagina que tienes una manzana. A
map
está transformando esa manzana,apple-juice
por ejemplo , en un mapeo uno a uno .Tome esa misma manzana y obtenga solo las semillas, eso es lo que
flatMap
hace, o una a muchas , una manzana como entrada, muchas semillas como salida.fuente
flatMap
caso, ¿primero recolecta las semillas de cada manzana en bolsas separadas, una bolsa por manzana, antes de verter todas las bolsas en una sola bolsa?flatmap
no era realmente vago, pero desde java-10 es vagoflatMap + lazy
, apuesto a que habrá algunas respuestas.map () y flatMap ()
map()
Simplemente toma una función un parámetro lambda donde T es un elemento y R el elemento de retorno construido utilizando T. Al final tendremos una secuencia con objetos de tipo R. Un ejemplo simple puede ser:
Simplemente toma los elementos 1 a 5 de Tipo
Integer
, usa cada elemento para construir un nuevo elemento a partir de tipoString
con valor"prefix_"+integer_value
y lo imprime.flatMap()
Es útil saber que flatMap () toma una función
F<T, R>
dondeT es un tipo a partir del cual se puede construir un Stream desde / con . Puede ser una Lista (T.stream ()), una matriz (Arrays.stream (someArray)), etc. cualquier cosa desde la cual un Stream puede ser con / o forma. en el siguiente ejemplo, cada desarrollador tiene muchos idiomas, por lo que el desarrollador. Idiomas es una lista y utilizará un parámetro lambda.
R es el flujo resultante que se construirá utilizando T. Sabiendo que tenemos muchas instancias de T, naturalmente tendremos muchos flujos de R. Todos estos flujos del tipo R ahora se combinarán en un solo flujo 'plano' del tipo R .
Ejemplo
Los ejemplos de Bachiri Taoufiq ven su respuesta aquí son simples y fáciles de entender. Solo por claridad, digamos que tenemos un equipo de desarrolladores:
, con cada desarrollador conociendo muchos idiomas:
Aplicando Stream.map () en dev_team para obtener los idiomas de cada desarrollador:
te dará esta estructura:
que es básicamente a
List<List<Languages>> /Object[Languages[]]
. ¡No es muy bonita, ni Java8!con
Stream.flatMap()
usted puede 'aplanar' las cosas, ya que toma la estructura anteriory la convierte
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, que básicamente se puede usar comoList<Languages>/Language[]/etc
...así que al final, tu código tendría más sentido así:
o simplemente:
Cuándo usar map () y usar flatMap () :
Úselo
map()
cuando se supone que cada elemento de tipo T de su flujo debe asignarse / transformarse en un solo elemento de tipo R. El resultado es un mapeo de tipo (1 elemento inicial -> 1 elemento final) y un nuevo flujo de elementos de tipo R es regresado.Úselo
flatMap()
cuando se supone que cada elemento de tipo T de su flujo se asigna / transforma a una Colección de elementos de tipo R. El resultado es una asignación de tipo (1 elemento inicial -> n elementos finales) . Estas colecciones se fusionan (o aplanan ) en una nueva secuencia de elementos de tipo R. Esto es útil, por ejemplo, para representar bucles anidados .Pre Java 8:
Publicar Java 8
fuente
Mapa: este método toma una función como argumento y devuelve una nueva secuencia que consta de los resultados generados al aplicar la función pasada a todos los elementos de la secuencia.
Imaginemos que tengo una lista de valores enteros (1,2,3,4,5) y una interfaz de función cuya lógica es cuadrada del entero pasado. (e -> e * e).
salida:-
Como puede ver, una salida es una nueva secuencia cuyos valores son cuadrados de valores de la secuencia de entrada.
http://codedestine.com/java-8-stream-map-method/
FlatMap: - Este método toma una función como argumento, esta función acepta un parámetro T como argumento de entrada y devuelve una secuencia del parámetro R como valor de retorno. Cuando esta función se aplica a cada elemento de esta secuencia, produce una secuencia de nuevos valores. Todos los elementos de estas nuevas secuencias generadas por cada elemento se copian en una nueva secuencia, que será un valor de retorno de este método.
Imaginemos que tengo una lista de objetos de estudiantes, donde cada estudiante puede optar por múltiples materias.
salida:-
Como puede ver, una salida es una nueva secuencia cuyos valores son una colección de todos los elementos de las secuencias devueltas por cada elemento de la secuencia de entrada.
[S1, S2, S3] -> [{"historia", "matemáticas", "geografía"}, {"economía", "biología"}, {"ciencia", "matemáticas"}] -> tomar materias únicas - > [economía, biología, geografía, ciencia, historia, matemáticas]
http://codedestine.com/java-8-stream-flatmap-method/
fuente
.map es para mapeo A -> B
Convierte cualquier artículo
A
en cualquier artículoB
. Javadoc.flatMap es para A -> Stream <B> concatenando
--1 convierte cualquier elemento
A
enStream< B>
, luego --2 concatena todas las transmisiones en una transmisión (plana). JavadocNota 1: Aunque el último ejemplo se distribuye en una secuencia de primitivas (IntStream) en lugar de una secuencia de objetos (Stream), todavía ilustra la idea de
.flatMap
.Nota 2: a pesar del nombre, el método String.chars () devuelve ints. Entonces, la colección real será:,
[100, 111, 103, 99, 97, 116]
donde100
está el código de'd'
,111
es el código de'o'
etc. Nuevamente, con fines ilustrativos, se presenta como [d, o, g, c, a, t].fuente
Respuesta simple
La
map
operación se puede producir unaStream
deStream
.EXStream<Stream<Integer>>
flatMap
la operación solo produciráStream
algo. EXStream<Integer>
fuente
También una buena analogía puede ser con C # si está familiarizado con. Básicamente C #
Select
similar a Javamap
y C #SelectMany
JavaflatMap
. Lo mismo se aplica a Kotlin para colecciones.fuente
Esto es muy confuso para principiantes. La diferencia básica es que
map
emite un elemento para cada entrada en la lista yflatMap
es básicamente una operaciónmap
+flatten
. Para ser más claro, use flatMap cuando necesite más de un valor, por ejemplo, cuando espera que un bucle devuelva matrices, flatMap será realmente útil en este caso.He escrito un blog sobre esto, puedes consultarlo aquí .
fuente
Transmita operaciones
flatMap
ymap
acepte una función como entrada.flatMap
espera que la función devuelva una nueva secuencia para cada elemento de la secuencia y devuelve una secuencia que combina todos los elementos de las secuencias devueltas por la función para cada elemento. En otras palabras, conflatMap
, para cada elemento de la fuente, la función creará múltiples elementos. http://www.zoftino.com/java-stream-examples#flatmap-operationmap
espera que la función devuelva un valor transformado y devuelve una nueva secuencia que contiene los elementos transformados. En otras palabras, conmap
, para cada elemento de la fuente, la función creará un elemento transformado. http://www.zoftino.com/java-stream-examples#map-operationfuente
flatMap()
También aprovecha la evaluación parcial diferida de flujos. Leerá la primera secuencia y solo cuando sea necesario, pasará a la siguiente secuencia. El comportamiento se explica en detalle aquí: ¿Se garantiza que flatMap sea vago?fuente
Si piensa
map()
como una iteración (for
bucle de un nivel ),flatmap()
es una iteración de dos niveles (como unfor
bucle anidado ). (Ingrese cada elemento iteradofoo
, y hagafoo.getBarList()
e itere en esobarList
nuevamente)map()
: tomar una secuencia, hacer algo con cada elemento, recopilar el resultado único de cada proceso, generar otra secuencia. La definición de "hacer algo funciona" está implícita. Si el procesamiento de cualquier elemento da como resultadonull
,null
se utiliza para componer la secuencia final. Entonces, el número de elementos en el flujo resultante será igual al número de flujo de entrada.flatmap()
: tome una secuencia de elementos / secuencias y una función (definición explícita), aplique la función a cada elemento de cada secuencia y recopile toda la secuencia intermedia resultante para que sea una secuencia mayor ("aplanamiento"). Si el procesamiento de cualquier elemento da como resultadonull
, se proporciona una secuencia vacía al paso final de "aplanamiento". El número de elementos en la secuencia resultante es el total de todos los elementos participantes en todas las entradas, si la entrada es varias secuencias.fuente