La réduction normale est censée combiner deux valeurs immuables telles que int, double, etc. et en produire une nouvelle; c'est une réduction immuable . En revanche, la méthode collect est conçue pour muter un conteneur pour accumuler le résultat qu'il est censé produire.
Pour illustrer le problème, supposons que vous souhaitiez réaliser en Collectors.toList()
utilisant une simple réduction comme
List<Integer> numbers = stream.reduce(
new ArrayList<Integer>(),
(List<Integer> l, Integer e) -> {
l.add(e);
return l;
},
(List<Integer> l1, List<Integer> l2) -> {
l1.addAll(l2);
return l1;
});
C'est l'équivalent de Collectors.toList()
. Cependant, dans ce cas, vous modifiez le fichier List<Integer>
. Comme nous le savons, le ArrayList
n'est pas thread-safe, et il n'est pas sûr d'ajouter / supprimer des valeurs pendant l'itération, de sorte que vous obtiendrez soit une exception simultanée, ArrayIndexOutOfBoundsException
soit tout type d'exception (en particulier lorsqu'il est exécuté en parallèle) lorsque vous mettez à jour la liste ou le combineur essaie de fusionner les listes parce que vous faites muter la liste en y accumulant (en ajoutant) les nombres entiers. Si vous voulez rendre ce thread-safe, vous devez passer une nouvelle liste à chaque fois, ce qui nuirait aux performances.
En revanche, les Collectors.toList()
travaux de la même manière. Cependant, il garantit la sécurité des threads lorsque vous accumulez les valeurs dans la liste. De la documentation de la collect
méthode :
Effectue une opération de réduction mutable sur les éléments de ce flux à l'aide d'un collecteur. Si le flux est parallèle et que le collecteur est simultané, et que le flux n'est pas ordonné ou que le collecteur n'est pas ordonné, une réduction simultanée sera effectuée. Lorsqu'ils sont exécutés en parallèle, de multiples résultats intermédiaires peuvent être instanciés, peuplés et fusionnés de manière à maintenir l'isolement des structures de données mutables. Par conséquent, même lorsqu'elle est exécutée en parallèle avec des structures de données non thread-safe (telles que ArrayList), aucune synchronisation supplémentaire n'est nécessaire pour une réduction parallèle.
Donc, pour répondre à votre question:
Quand utiliseriez-vous collect()
vs reduce()
?
si vous avez des valeurs immuables telles que ints
, doubles
, Strings
puis la réduction normale fonctionne très bien. Cependant, si vous avez reduce
vos valeurs dans disons une List
(structure de données mutable), vous devez utiliser la réduction mutable avec la collect
méthode.