map () e flatMap ()
map()
Prende solo una funzione un parametro lambda in cui T è elemento e R l'elemento di ritorno creato usando T. Alla fine avremo un flusso con oggetti di tipo R. Un semplice esempio può essere:
Stream
.of(1,2,3,4,5)
.map(myInt -> "preFix_"+myInt)
.forEach(System.out::println);
Prende semplicemente gli elementi da 1 a 5 di Tipo Integer
, usa ogni elemento per costruire un nuovo elemento dal tipo String
con valore "prefix_"+integer_value
e lo stampa.
flatMap()
È utile sapere che flatMap () assume una funzione in F<T, R>
cui
T è un tipo da cui è possibile creare uno stream da / con . Può essere un elenco (T.stream ()), un array (Arrays.stream (someArray)), ecc. Qualsiasi cosa da cui uno Stream può essere con / o modulo. nell'esempio seguente ogni sviluppatore ha molte lingue, quindi dev. Lingue è un elenco e utilizzerà un parametro lambda.
R è il flusso risultante che verrà creato usando T. Sapendo che abbiamo molti casi di T, avremo naturalmente molti flussi da R. Tutti questi flussi dal tipo R ora saranno combinati in un singolo flusso "piatto" dal tipo R .
Esempio
Gli esempi di Bachiri Taoufiq vedono la sua risposta qui sono semplici e facili da capire. Per chiarezza, diciamo solo che abbiamo un team di sviluppatori:
dev_team = {dev_1,dev_2,dev_3}
, con ogni sviluppatore che conosce molte lingue:
dev_1 = {lang_a,lang_b,lang_c},
dev_2 = {lang_d},
dev_2 = {lang_e,lang_f}
Applicando Stream.map () su dev_team per ottenere le lingue di ogni sviluppatore:
dev_team.map(dev -> dev.getLanguages())
ti darà questa struttura:
{
{lang_a,lang_b,lang_c},
{lang_d},
{lang_e,lang_f}
}
che è fondamentalmente un List<List<Languages>> /Object[Languages[]]
. Non molto carino, né simile a Java8 !!
con Stream.flatMap()
te puoi 'appiattire' le cose mentre prende la struttura sopra
e la trasforma in {lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, che può fondamentalmente essere usata come List<Languages>/Language[]/etc
...
quindi alla fine, il tuo codice avrebbe più senso in questo modo:
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 semplicemente:
dev_team
.stream() /* {dev_1,dev_2,dev_3} */
.flatMap(dev -> dev.getLanguages().stream()) /* {lang_a,...,lang_d, lang_e, lang_f} */
.doWhateverWithYourNewStreamHere();
Quando utilizzare map () e flatMap () :
Utilizzare map()
quando si suppone che ogni elemento di tipo T del flusso sia mappato / trasformato in un singolo elemento di tipo R. Il risultato è una mappatura di tipo (1 elemento iniziale -> 1 elemento finale) e un nuovo flusso di elementi di tipo R viene restituito.
Utilizzare flatMap()
quando si suppone che ogni elemento di tipo T del flusso sia mappato / trasformato in raccolte di elementi di tipo R. Il risultato è una mappatura di tipo (1 elemento iniziale -> n elementi finali) . Queste raccolte vengono quindi unite (o appiattite ) in un nuovo flusso di elementi di tipo R. Ciò è utile, ad esempio, per rappresentare cicli nidificati .
Pre Java 8:
List<Foo> myFoos = new ArrayList<Foo>();
for(Foo foo: myFoos){
for(Bar bar: foo.getMyBars()){
System.out.println(bar.getMyName());
}
}
Posta 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
.