La differenza tra map () e flatMap ()

1. Panoramica

Le API map () e flatMap () derivano da linguaggi funzionali. In Java 8, puoi trovarli in Optional, Stream e CompletableFuture (anche se con un nome leggermente diverso).

Gli stream rappresentano una sequenza di oggetti, mentre gli optionals sono classi che rappresentano un valore che può essere presente o assente. Tra le altre operazioni di aggregazione, abbiamo i metodi map () e flatMap () .

Nonostante entrambi abbiano gli stessi tipi di reso , sono abbastanza diversi. Spieghiamo queste differenze analizzando alcuni esempi di stream e optionals.

2. Mappa e Flatmap in Optionals

Il metodo map () funziona bene con Opzionale , se la funzione restituisce il tipo esatto di cui abbiamo bisogno:

Optional s = Optional.of("test"); assertEquals(Optional.of("TEST"), s.map(String::toUpperCase));

Tuttavia, in casi più complessi ci potrebbe essere fornita una funzione che restituisce anche un Opzionale . In questi casi, l'uso di map () porterebbe a una struttura nidificata, poiché l' implementazione map () esegue internamente un wrapping aggiuntivo.

Vediamo un altro esempio per capire meglio questa situazione:

assertEquals(Optional.of(Optional.of("STRING")), Optional .of("string") .map(s -> Optional.of("STRING")));

Come possiamo vedere, finiamo con la struttura nidificata Opzionale . Sebbene funzioni, è piuttosto ingombrante da usare e non fornisce alcuna sicurezza nulla aggiuntiva, quindi è meglio mantenere una struttura piatta.

Questo è esattamente ciò che flatMap () ci aiuta a fare:

assertEquals(Optional.of("STRING"), Optional .of("string") .flatMap(s -> Optional.of("STRING")));

3. Mappa e flatmap negli stream

Entrambi i metodi funzionano in modo simile per Opzionale .

Il metodo map () avvolge la sequenza sottostante in un'istanza Stream , mentre il metodo flatMap () consente di evitare Stream annidato struttura.

Nell'esempio seguente, map () produce uno Stream costituito dai risultati dell'applicazione del metodo toUpperCase () agli elementi dello Stream di input :

List myList = Stream.of("a", "b") .map(String::toUpperCase) .collect(Collectors.toList()); assertEquals(asList("A", "B"), myList);

map () funziona abbastanza bene in un caso così semplice, ma cosa succede se abbiamo qualcosa di più complesso come un elenco di elenchi come input.

Vediamo come funziona:

List
    
      list = Arrays.asList( Arrays.asList("a"), Arrays.asList("b")); System.out.println(list);
    

Questo frammento stampa un elenco di elenchi [[a], [b]].

Ora usiamo flatMap () :

System.out.println(list .stream() .flatMap(Collection::stream) .collect(Collectors.toList()));

Il risultato di uno snippet di questo tipo verrà convertito in [a, b].

T ha flatMap () metodo prima appiattisce l'ingresso Flusso di flussi ad un flusso di Corde (per ulteriori circa appiattimento, vedi l'articolo). Successivamente funziona in modo simile al metodo map () .

4. Conclusione

Java 8 ci dà l'opportunità di utilizzare i metodi map () e flatMap () originariamente utilizzati nei linguaggi funzionali.

Possiamo invocarli su Stream e Optionals. Questi metodi ci aiutano a ottenere oggetti mappati applicando la funzione di mappatura fornita.

Come sempre, puoi controllare gli esempi forniti in questo articolo su GitHub.