La différence entre map () et flatMap ()

1. Vue d'ensemble

Les API map () et flatMap () proviennent de langages fonctionnels. Dans Java 8, vous pouvez les trouver dans Optional, Stream et dans CompletableFuture (bien que sous un nom légèrement différent).

Les flux représentent une séquence d'objets, tandis que les options sont des classes qui représentent une valeur qui peut être présente ou absente. Parmi les autres opérations d'agrégation, nous avons les méthodes map () et flatMap () .

Malgré le fait que les deux ont les mêmes types de retour , ils sont assez différents. Expliquons ces différences en analysant quelques exemples de flux et d'options.

2. Carte et Flatmap dans les options

La méthode map () fonctionne bien avec Optional - si la fonction renvoie le type exact dont nous avons besoin:

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

Cependant, dans des cas plus complexes, nous pourrions recevoir une fonction qui renvoie également une option . Dans de tels cas, l'utilisation de map () conduirait à une structure imbriquée, car l' implémentation de map () effectue un wrapping supplémentaire en interne.

Voyons un autre exemple pour mieux comprendre cette situation:

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

Comme on peut le voir, on se retrouve avec la structure imbriquée Facultatif . Bien que cela fonctionne, il est assez lourd à utiliser et ne fournit aucune sécurité nulle supplémentaire, il est donc préférable de garder une structure plate.

C'est exactement ce que flatMap () nous aide à faire:

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

3. Carte et Flatmap dans les flux

Les deux méthodes fonctionnent de la même manière pour Optional .

La méthode map () encapsule la séquence sous-jacente dans une instance Stream , tandis que la méthode flatMap () permet d'éviter un Stream imbriqué structure.

Dans l'exemple suivant, map () produit un Stream constitué des résultats de l'application de la méthode toUpperCase () aux éléments du Stream d' entrée :

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

map () fonctionne plutôt bien dans un cas aussi simple, mais que se passe-t-il si nous avons quelque chose de plus complexe comme une liste de listes comme entrée.

Voyons voir comment ça fonctionne:

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

Cet extrait de code imprime une liste de listes [[a], [b]].

Maintenant, utilisons un flatMap () :

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

Le résultat d'un tel extrait de code sera aplati à [a, b].

T il flatMap () méthode aplatit d'abord l'entrée flux de cours d' eau à un flux de cordes (pour plus d' informations aplatissement, voir l'article). Par la suite, il fonctionne de manière similaire à la méthode map () .

4. Conclusion

Java 8 nous donne la possibilité d'utiliser les méthodes map () et flatMap () qui étaient à l'origine utilisées dans les langages fonctionnels.

Nous pouvons les invoquer sur Streams et Optionals. Ces méthodes nous aident à obtenir des objets mappés en appliquant la fonction de mappage fournie.

Comme toujours, vous pouvez consulter les exemples fournis dans cet article sur GitHub.