Quelle est la différence entre la Collecte.stream().forEach() et de la Collection.forEach()?
Je comprends que .stream()
, je peux utiliser les opérations de la chaîne comme .filter()
ou de l'utilisation parallèle de flux. Mais quelle est la différence entre eux, si j'ai besoin de réaliser de petites opérations (par exemple, l'impression, les éléments de la liste)?
collection.stream().forEach(System.out::println);
collection.forEach(System.out::println);
Vous devez vous connecter pour publier un commentaire.
Pour les cas simples comme celui qui est illustré, ils sont essentiellement les mêmes. Cependant, il existe un certain nombre de différences subtiles qui peuvent être importants.
Un problème avec la commande. Avec
Stream.forEach
, la commande est undefined. Il est peu probable de se produire avec séquentielle des ruisseaux, encore, c'est dans le cahier des charges pourStream.forEach
l'exécution arbitraire de l'ordre. Cela ne se produisent fréquemment dans les ruisseaux parallèles. En revanche,Iterable.forEach
est toujours exécuté dans l'itération de l'ordre de laIterable
, s'il est spécifié.Un autre problème est les effets secondaires. L'action spécifiée dans
Stream.forEach
est nécessaire pour être à la non-ingérence. (Voir la java.util.flux de paquet doc.)Iterable.forEach
a potentiellement moins de restrictions. Pour les collections enjava.util
,Iterable.forEach
utilisent généralement que la collectionIterator
, dont la plupart sont conçus pour être fail-fast et qui vont se jeterConcurrentModificationException
si la collection est structurellement modifiée au cours de l'itération. Toutefois, des modifications qui ne sont pas structurelles sont autorisés au cours d'une itération. Par exemple, le Liste de tableaux de documentation de classe dit "simplement en définissant la valeur d'un élément n'est pas une modification structurelle." Ainsi, l'action pourArrayList.forEach
est autorisé à définir des valeurs dans le sous-jacentArrayList
sans problèmes.Simultanée de l'collections sont encore différentes. Au lieu de fail-fast, ils sont conçus pour être faiblement cohérente. La définition complète est à ce lien. Brièvement, cependant, envisager
ConcurrentLinkedDeque
. L'action passée à sonforEach
méthode est le droit de modifier le sous-jacent deque, même structurellement, etConcurrentModificationException
n'est jamais levée. Toutefois, la modification qui se produit peut ou peut ne pas être visible dans cette itération. (D'où le "faible" de la cohérence.)Encore une autre différence est visible que si
Iterable.forEach
est de parcourir un synchronisé collection. Sur cette collection,Iterable.forEach
prend le verrouillage de la collection une fois et qu'elle détient dans tous les appels à la méthode d'action. LeStream.forEach
appel utilise la collection spliterator, qui ne se verrouille pas, et qui s'appuie sur la vigueur de la règle de non-ingérence. La collection de la sauvegarde de l'flux peut être modifié au cours d'une itération, et si elle l'est, uneConcurrentModificationException
ou un comportement incohérent pourraient en résulter.Iterable.forEach takes the collection's lock
. Où se trouve cette information? Je ne suis pas en mesure de trouver un tel comportement dans le JDK sources.ArrayList
ont assez stricte vérification pour les modifications simultanées, et ils sont donc souvent jeterConcurrentModificationException
. Mais ce n'est pas garanti, en particulier pour les filières parallèles. Au lieu de CME vous risquez d'obtenir une réponse inattendue. Tenir également compte de la non-modification de la structure du flux de la source. Pour les flux parallèles, vous ne savez pas ce thread sera procédé à un élément particulier, ni si elle a été traitée à la fois, c'est modifié. Ceci définit une condition de course, où vous pourriez obtenir des résultats différents à chaque exécution, et de ne jamais obtenir une CME.Cette réponse concerne les performances des implémentations différentes de la boucle. Son seul peu pertinents pour les boucles que l'on appelle TRÈS SOUVENT (comme des millions d'appels). Dans la plupart des cas, le contenu de la boucle est de loin le plus cher de l'élément. Pour les situations où vous boucle vraiment souvent, c'est peut-être encore d'intérêt.
Vous devrez répéter cette des tests dans le système cible, comme c'est la mise en œuvre spécifique, (l'intégralité du code source).
- Je exécuter openjdk version 1.8.0_111 sur un rapide machine Linux.
J'ai écrit un test de boucle, de 10^6 fois sur une Liste à l'aide de ce code avec des tailles variables pour
integers
(10^0 -> 10^5 entrées).Les résultats sont ci-dessous, la méthode la plus rapide varie en fonction de la quantité d'entrées dans la liste.
Mais toujours dans les pires situations, en boucle de plus de 10^5 entrées 10^6 fois pris 100 secondes pour le pire artiste, d'autres considérations sont de plus en plus important dans pratiquement toutes les situations.
Voici mes horaires: de millisecondes /fonction /nombre d'entrées dans la liste.
Chaque course est de 10^6 boucles.
Si vous répétez l'expérience, j'ai posté le l'intégralité du code source. Merci de ne modifier cette réponse et de vous ajouter résultats avec une notation du système testé.
(MacBook Pro 2,5 GHz Intel Core i7, 16 GO, macOS 10.12.6)
Il n'y a pas de différence entre les deux vous avez mentionné, au moins sur le plan conceptuel, la
Collection.forEach()
est juste une abréviation.À l'intérieur de l'
stream()
version a un peu plus de frais généraux en raison de la création de l'objet, mais en regardant le temps d'exécution il ni a une surcharge de là.Les deux implémentations de la fin de l'itération sur les
collection
contenu une fois, et pendant l'itération imprimer l'élément.Stream
en cours de création ou les objets individuels? Autant que je sache, unStream
ne pas dupliquer les éléments.