En Java 8, quelle est la différence entre les méthodes Stream.map()
et Stream.flatMap()
?
java
java-8
java-stream
cassiomoline
la source
la source
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
le mappeur lambda retourneR
,flatMap
le mappeur lambda renvoie aStream
deR
(Stream<R>
). Les flux renvoyés par leflatMap
mappeur de sont effectivement concaténés. Sinon, les deuxmap
et leflatMap
retourStream<R>
; la différence est ce que les lambdas mappeur retour,R
contreStream<R>
.Réponses:
Les deux
map
etflatMap
peuvent être appliqués à unStream<T>
et ils renvoient tous les deux unStream<R>
. La différence est que l'map
opération produit une valeur de sortie pour chaque valeur d'entrée, tandis queflatMap
opération produit un nombre arbitraire (zéro ou plus) pour chaque valeur d'entrée.Cela se reflète dans les arguments de chaque opération.
L'
map
opération prendFunction
, qui est appelé pour chaque valeur dans le flux d'entrée et produit une valeur de résultat, qui est envoyée au flux de sortie.L'
flatMap
opération prend une fonction qui veut conceptuellement consommer une valeur et produire un nombre arbitraire de valeurs. Cependant, en Java, il est difficile pour une méthode de renvoyer un nombre arbitraire de valeurs, car les méthodes ne peuvent renvoyer que zéro ou une valeur. On pourrait imaginer une API où la fonction de mappageflatMap
prend une valeur et retourne un tableau ou unList
des valeurs, qui sont ensuite envoyées à la sortie. Étant donné qu'il s'agit de la bibliothèque de flux, un moyen particulièrement approprié de représenter un nombre arbitraire de valeurs de retour est que la fonction de mappage elle-même retourne un flux! Les valeurs du flux renvoyé par le mappeur sont drainées du flux et transmises au flux de sortie. Les "blocs" de valeurs renvoyées par chaque appel à la fonction de mappage ne sont pas du tout distingués dans le flux de sortie, donc la sortie aurait été "aplatie".L'utilisation typique est que la fonction de mappage de
flatMap
retourStream.empty()
si elle veut envoyer des valeurs nulles, ou quelque chose commeStream.of(a, b, c)
si elle veut retourner plusieurs valeurs. Mais bien sûr, tout flux peut être retourné.la source
flatMap
opération est exactement l'opposé de plat. Encore une fois, laissez aux informaticiens le soin de tourner la tête. Comme une fonction «transparente» signifiant que vous ne pouvez rien voir de ce qu'elle fait, juste les résultats, tout en disant familièrement que vous voulez qu'un processus soit transparent signifie que vous voulez que chaque partie de celui-ci soit vue.Stream.flatMap
, comme on peut le deviner par son nom, est la combinaison d'unmap
et d'uneflat
opération. Cela signifie que vous appliquez d'abord une fonction à vos éléments, puis l'aplatissez.Stream.map
applique uniquement une fonction au flux sans aplatir le flux.Pour comprendre en quoi consiste l' aplatissement d' un flux, considérons une structure comme celle
[ [1,2,3],[4,5,6],[7,8,9] ]
qui a "deux niveaux". Aplatissant ce moyen de transformation dans une structure « un niveau »:[ 1,2,3,4,5,6,7,8,9 ]
.la source
Je voudrais donner 2 exemples pour avoir un point de vue plus pratique:
Premier exemple d'utilisation de la carte:
Rien de spécial dans le premier exemple, un
Function
est appliqué pour renvoyer leString
en majuscule.Deuxième exemple utilisant
flatMap
:Dans le deuxième exemple, un flux de liste est transmis. Ce n'est PAS un flux d'entiers!
Si une fonction de transformation doit être utilisée (via une carte), le flux doit d'abord être aplati en quelque chose d'autre (un flux de nombres entiers).
Si flatMap est supprimé, l'erreur suivante est renvoyée: L'opérateur + n'est pas défini pour la liste des types d'arguments, int.
Il n'est PAS possible d'appliquer + 1 sur une liste de nombres entiers!
la source
Stream<Integer>
plutôt qu'un flux deInteger
.Veuillez parcourir l'intégralité du message pour avoir une idée claire,
map vs flatMap:
Pour renvoyer une longueur de chaque mot d'une liste, nous ferions quelque chose comme ci-dessous.
Version courte donnée ci-dessous
Lorsque nous collectons deux listes, données ci-dessous
Sans carte plate => [1,2], [1,1] => [[1,2], [1,1]] Ici deux listes sont placées à l'intérieur d'une liste, donc la sortie sera une liste contenant des listes
Avec plan plat => [1,2], [1,1] => [1,2,1,1] Ici, deux listes sont aplaties et seules les valeurs sont placées dans la liste, donc la sortie sera une liste contenant uniquement des éléments
Fondamentalement, il fusionne tous les objets en un
## La version détaillée a été donnée ci-dessous: -
Par exemple: -
Considérons une liste ["STACK", "OOOVVVER"] et nous essayons de renvoyer une liste comme ["STACKOVER"] (en ne renvoyant que des lettres uniques de cette liste) Initialement, nous ferions quelque chose comme ci-dessous pour renvoyer un liste ["STACKOVER"] dans ["STACK", "OOOVVVER"]
Ici, le problème est que Lambda passé à la méthode map renvoie un tableau de chaînes pour chaque mot, donc le flux renvoyé par la méthode map est en fait de type Stream, mais ce dont nous avons besoin est Stream pour représenter un flux de caractères, l'image ci-dessous illustre le problème.
Figure A:
Vous pourriez penser que, nous pouvons résoudre ce problème en utilisant une carte plate,
OK, voyons comment résoudre ce problème en utilisant map et Arrays.stream Tout d'abord, vous aurez besoin d'un flux de caractères au lieu d'un flux de tableaux. Il existe une méthode appelée Arrays.stream () qui prendrait un tableau et produirait un flux, par exemple:
Ce qui précède ne fonctionne toujours pas, car nous nous retrouvons maintenant avec une liste de flux (plus précisément, Stream>). À la place, nous devons d'abord convertir chaque mot en un tableau de lettres individuelles, puis transformer chaque tableau en un flux distinct
En utilisant flatMap, nous devrions pouvoir résoudre ce problème comme ci-dessous:
flatMap effectuerait le mappage de chaque tableau non pas avec un flux mais avec le contenu de ce flux. Tous les flux individuels qui seraient générés lors de l'utilisation de map (Arrays :: stream) sont fusionnés en un seul flux. La figure B illustre l'effet de l'utilisation de la méthode flatMap. Comparez-le avec la carte de la figure A. Figure B
La méthode flatMap vous permet de remplacer chaque valeur d'un flux par un autre flux, puis joint tous les flux générés en un seul flux.
la source
Réponse en une ligne:
flatMap
aide à aplatir unCollection<Collection<T>>
en unCollection<T>
. De la même manière, il s'aplatira égalementOptional<Optional<T>>
enOptional<T>
.Comme vous pouvez le voir, avec
map()
seulement:Stream<List<Item>>
List<List<Item>>
et avec
flatMap()
:Stream<Item>
List<Item>
Voici le résultat du test du code utilisé juste en dessous:
Code utilisé :
la source
La fonction à laquelle vous passez
stream.map
doit renvoyer un objet. Cela signifie que chaque objet du flux d'entrée génère exactement un objet dans le flux de sortie.La fonction à laquelle vous passez
stream.flatMap
renvoie un flux pour chaque objet. Cela signifie que la fonction peut renvoyer n'importe quel nombre d'objets pour chaque objet d'entrée (y compris aucun). Les flux résultants sont ensuite concaténés en un flux de sortie.la source
Department
s dans votre organisation. Chaque département a entre 0 et nEmployee
s. Vous avez besoin d'un flux de tous les employés. Donc que fais-tu? Vous écrivez une méthode flatMap qui prend un service et renvoie un flux de ses employés.flatMap
? Je soupçonne que cela peut être accessoire et n'illustre pas le cas d'utilisation clé ou la raison de sonflatMap
existence. (Suite ci-dessous ...)flatMap
est de tenir compte des erreurs qui seraient présentes lors de l'utilisationmap
. Comment gérez-vous les cas où un ou plusieurs éléments de l'ensemble d'origine ne peuvent pas être mappés à un élément de sortie? En introduisant un ensemble intermédiaire (disons unOptional
ouStream
) pour chaque objet d'entrée,flatMap
vous permet d'exclure les objets d'entrée "non valides" (ou les "mauvaises pommes" dans l'esprit de stackoverflow.com/a/52248643/107158 ) de la ensemble final.pour une carte, nous avons une liste d'éléments et une (fonction, action) f donc:
et pour la carte plate nous avons une liste de liste d'éléments et nous avons une (fonction, action) f et nous voulons que le résultat soit aplati:
la source
J'ai le sentiment que la plupart des réponses ici compliquent le problème simple. Si vous comprenez déjà comment
map
travaux devraient être assez faciles à saisir.Il y a des cas où nous pouvons nous retrouver avec des structures imbriquées indésirables lors de l'utilisation
map()
, laflatMap()
méthode est conçue pour surmonter cela en évitant le wrapping.Exemples:
1
Nous pouvons éviter d'avoir des listes imbriquées en utilisant
flatMap
:2
où:
la source
List<Integer> result = Stream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(i -> i) .collect(Collectors.toList());
. Il devrait êtreStream.of(Arrays.asList(1), Arrays.asList(2, 3)) .flatMap(List::stream) .collect(Collectors.toList());
L'article d'Oracle sur Facultatif met en évidence cette différence entre la carte et la carte plate:
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
la source
Je ne suis pas très sûr d'être censé répondre à cela, mais chaque fois que je rencontre quelqu'un qui ne comprend pas cela, j'utilise le même exemple.
Imaginez que vous ayez une pomme. A
map
transforme cette pommeapple-juice
par exemple en une cartographie biunivoque.Prenez cette même pomme et n'en retirez que les graines, c'est ce qui
flatMap
fait, ou une à plusieurs , une pomme en entrée, de nombreuses graines en sortie.la source
flatMap
cas, collectez-vous d'abord les graines de chaque pomme dans des sacs séparés, un sac par pomme, avant de verser tous les sacs dans un seul sac?flatmap
n'était pas vraiment paresseux, mais depuis java-10 c'est paresseuxflatMap + lazy
, je parie qu'il y aura des réponses.map () et flatMap ()
map()
Prend simplement une fonction un paramètre lambda où T est l'élément et R l'élément de retour construit à l'aide de T. À la fin, nous aurons un flux avec des objets de type R. Un exemple simple peut être:
Il prend simplement les éléments 1 à 5 de Type
Integer
, utilise chaque élément pour construire un nouvel élément à partir de typeString
avec valeur"prefix_"+integer_value
et l'imprime.flatMap()
Il est utile de savoir que flatMap () prend une fonction
F<T, R>
oùT est un type à partir duquel un Stream peut être construit à partir de / avec . Ce peut être une List (T.stream ()), un tableau (Arrays.stream (someArray)), etc. tout ce dont un Stream peut être avec / ou forme. dans l'exemple ci-dessous, chaque dev a plusieurs langues, donc dev. Les langues sont une liste et utiliseront un paramètre lambda.
R est le flux résultant qui sera construit à l'aide de T. Sachant que nous avons de nombreuses instances de T, nous aurons naturellement de nombreux flux de R. Tous ces flux de type R seront désormais combinés en un seul flux `` plat '' de type R .
Exemple
Les exemples de Bachiri Taoufiq voir sa réponse ici sont simples et faciles à comprendre. Pour plus de clarté, disons simplement que nous avons une équipe de développeurs:
, chaque développeur connaissant plusieurs langues:
Appliquer Stream.map () sur dev_team pour obtenir les langues de chaque développeur:
vous donnera cette structure:
qui est essentiellement un
List<List<Languages>> /Object[Languages[]]
. Pas très joli, ni Java8 !!avec
Stream.flatMap()
vous pouvez `` aplatir '' les choses en prenant la structure ci-dessuset en la transformant
{lang_a, lang_b, lang_c, lang_d, lang_e, lang_f}
, qui peut essentiellement être utilisée commeList<Languages>/Language[]/etc
...donc à la fin, votre code aurait plus de sens comme ceci:
ou simplement:
Quand utiliser map () et flatMap () :
À utiliser
map()
lorsque chaque élément de type T de votre flux est censé être mappé / transformé en un seul élément de type R. Le résultat est un mappage de type (1 élément de départ -> 1 élément de fin) et un nouveau flux d'éléments de type R est retourné.À utiliser
flatMap()
lorsque chaque élément de type T de votre flux est censé être mappé / transformé en collections d'éléments de type R. Le résultat est un mappage de type (1 élément de début -> n éléments de fin) . Ces collections sont ensuite fusionnées (ou aplaties ) dans un nouveau flux d'éléments de type R. Ceci est utile par exemple pour représenter des boucles imbriquées .Pré Java 8:
Post Java 8
la source
Carte: - Cette méthode prend une fonction comme argument et retourne un nouveau flux composé des résultats générés en appliquant la fonction passée à tous les éléments du flux.
Imaginons, j'ai une liste de valeurs entières (1,2,3,4,5) et une interface de fonction dont la logique est le carré de l'entier passé. (e -> e * e).
production:-
Comme vous pouvez le voir, une sortie est un nouveau flux dont les valeurs sont des carrés de valeurs du flux d'entrée.
http://codedestine.com/java-8-stream-map-method/
FlatMap: - Cette méthode prend une fonction comme argument, cette fonction accepte un paramètre T comme argument d'entrée et retourne un flux de paramètre R comme valeur de retour. Lorsque cette fonction est appliquée à chaque élément de ce flux, elle produit un flux de nouvelles valeurs. Tous les éléments de ces nouveaux flux générés par chaque élément sont ensuite copiés dans un nouveau flux, qui sera une valeur de retour de cette méthode.
Imaginons, j'ai une liste d'objets étudiants, où chaque étudiant peut opter pour plusieurs sujets.
production:-
Comme vous pouvez le voir, une sortie est un nouveau flux dont les valeurs sont une collection de tous les éléments des flux renvoyés par chaque élément du flux d'entrée.
[S1, S2, S3] -> [{"histoire", "math", "géographie"}, {"économie", "biologie"}, {"science", "math"}] -> prendre des sujets uniques - > [économie, biologie, géographie, science, histoire, mathématiques]
http://codedestine.com/java-8-stream-flatmap-method/
la source
.map est pour le mappage A -> B
il convertit n'importe quel élément
A
en n'importe quel élémentB
. Javadoc.flatMap est pour A -> Stream <B> concatinating
il --1 convertit n'importe quel élément
A
enStream< B>
, puis --2 concatène tous les flux en un seul flux (plat). JavadocRemarque 1: Bien que ce dernier exemple se transforme en un flux de primitives (IntStream) au lieu d'un flux d'objets (Stream), il illustre toujours l'idée du
.flatMap
.Remarque 2: Malgré le nom, la méthode String.chars () renvoie des entiers. Ainsi, la collection réelle sera:,
[100, 111, 103, 99, 97, 116]
où100
est le code de'd'
,111
est le code de'o'
etc. Encore une fois, à des fins d'illustration, il est présenté comme [d, o, g, c, a, t].la source
Réponse simple.
L'
map
opération peut produire unStream
deStream
.EXStream<Stream<Integer>>
flatMap
l'opération ne produira queStream
quelque chose. EXStream<Integer>
la source
Une bonne analogie peut également être avec C # si vous êtes familier avec. Fondamentalement C #
Select
similaire à javamap
et C #SelectMany
javaflatMap
. Il en va de même pour Kotlin pour les collections.la source
C'est très déroutant pour les débutants. La différence de base est
map
émet un élément pour chaque entrée de la liste etflatMap
est fondamentalement une opérationmap
+flatten
. Pour être plus clair, utilisez flatMap lorsque vous avez besoin de plusieurs valeurs, par exemple lorsque vous vous attendez à ce qu'une boucle retourne des tableaux, flatMap sera vraiment utile dans ce cas.J'ai écrit un blog à ce sujet, vous pouvez le vérifier ici .
la source
Opérations de streaming
flatMap
etmap
acceptation d'une fonction en entrée.flatMap
attend de la fonction qu'elle renvoie un nouveau flux pour chaque élément du flux et renvoie un flux qui combine tous les éléments des flux renvoyés par la fonction pour chaque élément. En d'autres termes, avecflatMap
, pour chaque élément de la source, plusieurs éléments seront créés par la fonction. http://www.zoftino.com/java-stream-examples#flatmap-operationmap
attend que la fonction retourne une valeur transformée et retourne un nouveau flux contenant les éléments transformés. En d'autres termes, avecmap
, pour chaque élément de la source, un élément transformé sera créé par la fonction. http://www.zoftino.com/java-stream-examples#map-operationla source
flatMap()
tire également parti de l'évaluation paresseuse partielle des flux. Il lira le premier flux et uniquement lorsque cela sera nécessaire, ira au flux suivant. Le comportement est expliqué en détail ici: FlatMap est-il garanti d'être paresseux?la source
Si vous pensez
map()
comme une itération (for
boucle à un niveau ),flatmap()
est une itération à deux niveaux (comme unefor
boucle imbriquée ). (Entrez chaque élément itéréfoo
, et recommencezfoo.getBarList()
etbarList
recommencez)map()
: prendre un flux, faire quelque chose pour chaque élément, collecter le résultat unique de chaque processus, sortir un autre flux. La définition de "faire quelque chose" est implicite. Si le traitement d'un élément entraînenull
,null
est utilisé pour composer le flux final. Ainsi, le nombre d'éléments dans le flux résultant sera égal au nombre de flux d'entrée.flatmap()
: prendre un flux de éléments / flux et une fonction (définition explicite), appliquer la fonction à chaque élément de chaque flux, et collecter tous les flux intermédiaires résultants pour être un flux plus important ("flattening"). Si le traitement d'un élément entraînenull
, un flux vide est fourni à l'étape finale de l'aplatissement. Le nombre d'éléments dans le flux résultant est le total de tous les éléments participants dans toutes les entrées, si l'entrée est constituée de plusieurs flux.la source