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:
Stream
.of(1,2,3,4,5)
.map(myInt -> "preFix_"+myInt)
.forEach(System.out::println);
Simplemente toma los elementos 1 a 5 de Tipo Integer
, usa cada elemento para construir un nuevo elemento a partir de tipo String
con valor "prefix_"+integer_value
y lo imprime.
flatMap()
Es útil saber que flatMap () toma una función F<T, R>
donde
T 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:
dev_team = {dev_1,dev_2,dev_3}
, con cada desarrollador conociendo muchos idiomas:
dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_2 = {lang_e,lang_f}
Aplicando Stream.map () en dev_team para obtener los idiomas de cada desarrollador:
dev_team.map(dev -> dev.getLanguages())
te dará esta estructura:
{
{lang_a,lang_b,lang_c},
{lang_d},
{lang_e,lang_f}
}
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 anterior
y la convierte {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, que básicamente se puede usar como List<Languages>/Language[]/etc
...
así que al final, tu código tendría más sentido así:
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();
o simplemente:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
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:
List<Foo> myFoos = new ArrayList<Foo>();
for(Foo foo: myFoos){
for(Bar bar: foo.getMyBars()){
System.out.println(bar.getMyName());
}
}
Publicar Java 8
myFoos
.stream()
.flatMap(foo -> foo.getMyBars().stream())
.forEach(bar -> System.out.println(bar.getMyName()));
map :: Stream T -> (T -> R) -> Stream R
,flatMap :: Stream T -> (T -> Stream R) -> Stream R
.