Java 8 Itératif.forEach() vs boucle foreach
- Ce qui est le mieux la pratique en Java 8?
Java 8:
joins.forEach(join -> mIrc.join(mSession, join));
Java 7:
for (String join : joins) {
mIrc.join(mSession, join);
}
J'ai beaucoup de boucles for qui pourrait être "simplifié" avec des lambdas, mais est-il vraiment parti de leur utilisation? Serait-il améliorer leurs performances et la lisibilité?
MODIFIER
Je vais aussi étendre cette question à plus de méthodes. Je sais que vous ne pouvez pas retourner ou de rompre avec la fonction parent d'un lambda, et cela devrait également être pris en considération lors de la comparaison, mais est-il autre chose à être pris en compte?
- Je crois lamdas sont destinés à améliorer l'utilisation de processeurs multi-core. Si votre environnement cible est multi-core, je crois lamdas aura amélioration de la performance sur le java 7 pour la boucle.
- Il n'y a pas de réel avantage en termes de performance de l'un sur l'autre. La première option est quelque chose inspiré par FP (qui est couramment parlé comme plus "agréable" et "effacer" pour exprimer votre code). En réalité c'est plutôt le "style" de la question.
- dans ce cas, ce n'est pas pertinente. forEach n'est pas défini comme étant parallèles ou quoi que ce soit, de sorte que ces deux choses sont sémantiquement équivalents. Bien sûr, il est possible de mettre en œuvre une version parallèle de forEach (et on peut déjà être présents dans la bibliothèque standard), et dans un tel cas, la syntaxe de l'expression lambda serait très utile.
- L'instance sur laquelle forEach est appelé est un Flux (lambdadoc.net/api/java/util/stream/Stream.html). Pour demander une exécution parallèle on pourrait écrire des jointures.parallèle().forEach(...)
- Est
joins.forEach((join) -> mIrc.join(mSession, join));
vraiment une "simplification" defor (String join : joins) { mIrc.join(mSession, join); }
? Vous avez augmenté la ponctuation compter de 9 à 12, pour le bénéfice de cacher le type dejoin
. Ce que vous avez vraiment à faire est de mettre deux états sur une seule ligne. - La parenthèse n'est pas nécessaire sur le côté gauche de la lambda. De la sorte, peut être écrite comme: les jointures.forEach( join -> mIrc.join(mSession,l'adhésion);
- Question connexe: stackoverflow.com/questions/23218874/...
- Un autre point à considérer est le peu variable de capture de Java. Avec Stream.forEach(), vous ne pouvez pas mettre à jour les variables locales depuis leur capture rend finale, ce qui signifie que vous pouvez avoir avec un état de comportement dans le forEach lambda (sauf si vous êtes prêt pour une certaine laideur comme l'utilisation de la classe de variables d'état).
- dépend du cas d'utilisation.
- si vous avez besoin de la programmation parallèle activée, puis utiliser les flux d'autres sages simplement utiliser le trivial approche.
- La mise en œuvre du Parallélisme sans la nécessité comprendra excessive des frais généraux.
Vous devez vous connecter pour publier un commentaire.
La meilleure pratique consiste à utiliser
for-each
. En plus de violer le Keep It Simple, Stupid principe, le principe d'un nouveau genreforEach()
a au moins les insuffisances suivantes:Ne pouvez pas utiliser des variables final. Ainsi, le code suivant ne peut pas être transformé en un forEach lambda:
Ne peut pas gérer checked exceptions. Les Lambdas ne sont pas réellement interdit de jeter checked exceptions, mais les interfaces fonctionnelles comme
Consumer
ne pas déclarer tout. Par conséquent, tout code qui jette vérifié les exceptions doivent envelopper danstry-catch
ouThrowables.propagate()
. Mais même si vous le faites, il n'est pas toujours clairement ce qui se passe à la levée d'une exception. Il pourrait être avalé quelque part dans les entrailles deforEach()
Limité le contrôle du flux de. Un
return
dans un lambda est égal à uncontinue
dans un chacun, mais il n'y a pas l'équivalent d'unbreak
. Il est aussi difficile de faire des choses comme valeurs de retour, court-circuit, ou définir des indicateurs (ce qui aurait atténué les choses un peu, si ce n'était pas une violation de la pas de non-final variables la règle). "Ce n'est pas seulement une optimisation, mais c'est essentiel si l'on considère que certaines séquences (comme la lecture des lignes dans un fichier) peut avoir des effets secondaires, ou vous pouvez avoir une suite infinie."Peut exécuter en parallèle, qui est un horrible, horrible chose pour tous, mais les 0,1% de votre code qui doit être optimisé. Tout code parallèle doit être pensé (même si elle n'utilise pas les serrures, les volatiles, et d'autres particulièrement désagréable aspects de la traditionnelle multi-thread d'exécution). Aucun bug va être difficile à trouver.
Pourrait nuire à la performance d', parce que l'équipe ne peut pas optimiser forEach()+lambda dans la même mesure que la plaine de boucles, surtout maintenant que les lambdas sont nouveaux. Par "optimisation" je ne veux pas les frais généraux de l'appel à lambdas (qui est petite), mais à la plus sophistiquée d'analyse et de transformation de modernes compilateur JIT exécute sur l'exécution de code.
Si vous avez besoin de parallélisme, il est probablement beaucoup plus rapide et pas beaucoup plus difficile à utiliser un ExecutorService. Les ruisseaux sont à la fois automagical (lire: ne sais pas beaucoup au sujet de votre problème) et utiliser spécialisée (lire: inefficace pour le cas général) de parallélisation de la stratégie (fork-join de décomposition récursive).
Rend le débogage plus de confusion, en raison de la imbriquée à l'appel de la hiérarchie et, à dieu ne plaise, l'exécution en parallèle. Le débogueur peut avoir des problèmes d'affichage de variables à partir de l'environnement de code, et des choses comme par étape-ne peut pas fonctionner comme prévu.
Flux en général, sont plus difficiles à code, lire, et de débogage. En fait, cela est vrai de complexe "couramment" Api en général. La combinaison de complexe unique déclarations, l'utilisation excessive de médicaments génériques, et de l'absence de variables intermédiaires, concourent à produire de la confusion des messages d'erreur et de frustration pour le débogage. Au lieu de "cette méthode n'a pas une surcharge pour le type X", vous obtenez un message d'erreur plus proche de "quelque part, vous foiré les types, mais nous ne savons pas où, ni comment." De même, vous ne pouvez pas parcourir et examiner les choses dans un débogueur, aussi facilement que lorsque le code est divisé en plusieurs états, et les valeurs intermédiaires sont enregistrées dans des variables. Enfin, la lecture du code et de comprendre les types et le comportement à chaque étape de l'exécution peut être non négligeable.
Colle dehors comme un pouce endolori. Le langage Java a déjà le pour-chaque instruction. Pourquoi le remplacer par un appel de fonction? Pourquoi encourager les cacher effets secondaires quelque part dans les expressions? Pourquoi encourager les encombrants one-liners? Mélanger régulièrement pour-chaque et de nouvelles forEach bon gré mal gré est mauvais style. Le Code doit parler dans les expressions idiomatiques (modèles qui sont faciles à comprendre en raison de leur répétition), et le moins idiomes sont utilisés le plus clair, le code est et moins de temps est consacré à choisir quel idiome à utiliser (un grand moment de drain pour les perfectionnistes comme moi!).
Comme vous pouvez le voir, je ne suis pas un grand fan de la boucle forEach (), sauf dans les cas où cela a du sens.
Particulièrement choquant pour moi est le fait que
Stream
ne pas mettre en œuvreIterable
(malgré le fait d'avoir de la méthodeiterator
) et ne peut être utilisé dans un for-each, seulement avec un forEach(). Je recommande casting les cours d'eau en Iterables avec(Iterable<T>)stream::iterator
. Une meilleure alternative est d'utiliser StreamEx qui fixe un certain nombre de Flux API problèmes, y compris la mise en œuvre deIterable
.Cela dit,
forEach()
est utile pour:Atomiquement de parcourir un synchronisé liste. Avant cela, une liste générée avec
Collections.synchronizedList()
a été atomique à l'égard des choses comme obtenir ou de définir, mais n'était pas thread-safe lors de l'itération.L'exécution en parallèle (en utilisant le courant parallèle). Cela vous permet d'économiser quelques lignes de code vs à l'aide d'un ExecutorService, si votre problème correspond à la performance des hypothèses construites dans les cours d'eau et Spliterators.
Des conteneurs spécifiques qui, comme la synchronisation de liste, profiter d'être dans le contrôle de l'itération (même si cela est en grande partie théorique, les gens ne peuvent proposer d'autres exemples)
L'appel d'une fonction unique plus proprement en utilisant
forEach()
et une méthode de référence argument (c'est à dire,list.forEach (obj::someMethod)
). Cependant, gardez à l'esprit les points sur checked exceptions, de plus en plus difficile de débogage, et de réduire le nombre d'expressions que vous utilisez lors de l'écriture de code.Articles que j'ai utilisé pour référence:
EDIT: Ressemble à certaines de ses propositions pour les lambdas (comme http://www.javac.info/closures-v06a.html) résolu certains des problèmes que j'ai mentionnés (tout en ajoutant leurs propres complications, bien sûr).
forEach
est là pour encourager le style fonctionnel, c'est à dire à l'aide d'expressions sans effets secondaires. Si vous rencontrez la situation de laforEach
ne fonctionne pas bien avec votre effets secondaires vous devez avoir le sentiment que vous n'êtes pas utiliser le bon outil pour le travail. Alors la réponse est simple, c'est parce que votre sentiment est juste, alors restez dans la boucle for-each pour que. Le classiquefor
boucle n'est pas devenu obsolète...forEach
être utilisé sans effets secondaires?forEach
est le seul flux de fonctionnement prévu pour les effets secondaires, mais ce n'est pas pour les effets secondaires, comme votre code d'exemple, le comptage est une typiquereduce
opération. Je voudrais suggérer, comme une règle de thump, pour garder toutes les opérations qui manipule des variables locales ou n'aura d'influence sur le flux de contrôle (y compris la gestion des exceptions) dans un classiquefor
boucle. Concernant la question initiale, je pense, le problème vient du fait que quelqu'un utilise un flux où un simplefor
en boucle sur la source du ruisseau serait suffisant. L'utilisation d'un ruisseau oùforEach()
fonctionne uniquementforEach
serait approprié?for
boucles.forEach
pour résoudre un problème de comptage vous le faites mal. Le comptage peut être exprimée comme une réduction commemyList.stream().reduce(0, (count, str) -> count + 1, (count1, count2) -> count1 + count2);
Est-ce que la stylistique amélioration par rapport àfor-each
? Pas pour cet exemple, mais il estfor-each
une amélioration par rapport àmyList.size()
?<Stream>.count()
remplit le premier exemple.forEach
. Le fonctionnement de l'idiome est la réduction. La présentation d'une utilisation inappropriée cas pourforEach
et de prétendre ensuite qu'il est défectueux parce qu'il ne peut pas être utilisé pour résoudre elle est trompeuse.int counter = 0; for(String string : myList) counter++;
Stream.zip()
étaient encore autour de il y aurait une encombrants façon de gérer ce genre de problèmes, mais il serait quand même moche. Le plus élégant fonctionnel solution serait d'utiliser la récursivité, mais depuis que Java ne supporte pas la queue de la récursivité optimisation ce serait une mauvaise solution en Java..forEach()
, puis de lire cette réponse et qu'il ne soit pas sûr.. je ne veux pas que mon code accidentellement en cours d'exécution dans un autre thread en quelque sorte, sans m'en être conscientjava.lang.Iterable
interface, vous ne pouvez pas utiliserforEach
avec eux. Surtout pour un nouveau venu, il est plutôt difficile de comprendre pourquoiList
s sont Itératif, mais pas les tableaux!forEach()
est nécessairement liée à des effets secondaires, par définition (manipulation d'objets, l'impression, l'envoi de fichier sont aussi des effets secondaires). Et si c'est le cas, pourquoi essayer de "cacher" un les boucles foreach comme un "fonctionnelle" pseudo-expression?Stream
(comme Itérateur) est une utilisation de l'objet, alors qu'unIterable
doit produire un nouvelles itérateur sur chaque demande. Cela ne devrait pas être leStream
responsabilité, mais le source du flux (comme la Collection) peut mettre en œuvre.Iterable
est fondamentalement brisé: oui, il va travailler dans un "for-each", mais pas d'autres utilisations valides. (Exemple: nombre de Goyave fonctions de la bibliothèque prendreIterable
au lieu deCollection
que c'est plus abstrait, donc de manière plus générale & souple. Vous devriez être en mesure d'appeler n'importe quel nombre de ces fonctions.) De toute façon, c'est une bonne liste de référence concernant la for-each vsforEach()
, donc merci pour la compilation!L'avantage vient en compte lors de toutes les opérations peuvent être exécutées en parallèle. (Voir http://java.dzone.com/articles/devoxx-2012-java-8-lambda-and - la partie interne et externe de l'itération)
Le principal avantage de mon point de vue est que la mise en œuvre de ce qui est à faire à l'intérieur de la boucle peut être défini sans avoir à décider si elle sera exécutée en parallèle ou séquentielle
Si vous voulez que votre boucle à être exécutées en parallèle, vous pouvez simplement écrire
Vous aurez à écrire un peu de code supplémentaire pour la manipulation du fil etc.
Remarque: Pour ma réponse, je suppose rejoint la mise en œuvre de la
java.util.Stream
interface. Si rejoint implémente seulement lesjava.util.Iterable
interface ce n'est plus vrai.map
&fold
qui ne sont pas vraiment liés à des lambdas.Stream#forEach
etIterable#forEach
ne sont pas la même chose. L'OP est de demander à propos deIterable#forEach
.joins
est la mise en œuvre deIterable
au lieu deStream
? À partir d'un couple de choses que j'ai lues, OP devraient être en mesure de fairejoins.stream().forEach((join) -> mIrc.join(mSession, join));
etjoins.parallelStream().forEach((join) -> mIrc.join(mSession, join));
sijoins
implémenteIterable
Lors de la lecture de cette question, on peut avoir l'impression, que
Iterable#forEach
en combinaison avec les expressions lambda est un raccourci/remplacement pour l'écriture traditionnelle boucle for-each. Ce n'est tout simplement pas vrai. Ce code à partir de l'OP:est pas conçu comme un raccourci pour l'écriture
et devrait certainement pas être utilisé de cette façon. Au lieu de cela, il est conçu comme un raccourci (même si c'est pas exactement le même) pour l'écriture
Et c'est comme un remplacement pour la suite de Java 7 code:
Remplacer le corps de la boucle, avec une interface fonctionnelle, comme dans les exemples ci-dessus, rend votre code plus explicite: "Vous dites que (1) le corps de la boucle n'affecte pas le code environnant et le contrôle de flux, et (2) le corps de la boucle peut être remplacée par une autre implémentation de la fonction, sans affecter le code environnant. N'étant pas en mesure d'accéder non les variables final de l'extérieur de la portée n'est pas un déficit de fonctions/lambdas, c'est un fonction qui distingue la sémantique de
Iterable#forEach
de la sémantique de la traditionnelle boucle for-each. Une fois que l'on s'habitue à la syntaxe deIterable#forEach
, il rend le code plus lisible, parce que vous obtenez immédiatement cette information supplémentaire au sujet du code.Traditionnelles boucles for-each va certainement rester bonnes pratiques (pour éviter le terme galvaudé "les meilleures pratiques") en Java. Mais cela ne veut pas dire, que
Iterable#forEach
devrait être considéré comme une mauvaise pratique ou de mauvais style. Il est toujours de bonne pratique, à utiliser le bon outil pour faire le travail, et cela inclut le mélange traditionnel pour chaque boucles avecIterable#forEach
, où il fait sens.Depuis les inconvénients de la
Iterable#forEach
il a déjà été question dans ce fil, voici quelques raisons pour lesquelles vous pourriez probablement vouloir utiliserIterable#forEach
:Pour rendre votre code plus explicite: Comme décrit ci-dessus,
Iterable#forEach
peut de rendre votre code plus explicite et lisible dans certaines situations.Pour rendre votre code plus extensible et facile à entretenir: à l'Aide d'une fonction comme le corps d'une boucle permet de remplacer cette fonction avec différentes implémentations (voir Modèle De Stratégie). Vous pourriez par exemple facilement remplacer l'expression lambda avec un appel de méthode, qui peuvent être remplacées par des sous-classes:
Alors vous pourriez fournir des stratégies par défaut à l'aide d'un enum, qui implémente l'interface fonctionnelle. Non seulement cela rend votre code plus extensible, il augmente également la facilité de maintenance, car il dissocie la boucle de la mise en œuvre de la boucle de la déclaration.
Pour rendre votre code plus debuggable: Séparant la boucle de la mise en œuvre de la déclaration peut également faciliter le débogage plus facile, parce que vous pourriez avoir spécialisée de débogage de la mise en œuvre, qui permet d'afficher les messages de débogage, sans le besoin d'encombrer votre code principal avec
if(DEBUG)System.out.println()
. Le débogage de la mise en œuvre pourrait, par exemple, être un délégué, que orne de la fonction réelle mise en œuvre.Pour optimiser la performance de code critique: Contrairement à certaines affirmations contenues dans ce fil,
Iterable#forEach
ne déjà fournir de meilleures performances que les méthodes classiques pour chaque boucle, au moins lors de l'utilisation de liste de tableaux et de course Hotspot "client" de mode. Bien que ce gain de performance est faible et négligeable pour la plupart des cas, il existe des situations où cette performance supplémentaire peut faire la différence. E. g. bibliothèque responsables aurez certainement envie d'évaluer, si certains de leurs existant boucle implémentations devraient être remplacés parIterable#forEach
.À propos des faits, j'ai fait quelques micro-benchmarks avec Étrier. Voici le code de test (dernière Étrier de git est nécessaire):
Et voici les résultats:
Lors de l'exécution avec le "client",
Iterable#forEach
surpasse le traditionnel pour une boucle sur une liste de tableaux, mais il est encore plus lent que directement à parcourir un tableau. Lors de l'exécution avec le "serveur", la performance de l'ensemble des approches est la même.De fournir un support optionnel pour l'exécution en parallèle: Il a déjà été dit ici, que la possibilité d'exécuter l'interface fonctionnelle de
Iterable#forEach
en parallèle à l'aide de flux, est certainement un aspect important. DepuisCollection#parallelStream()
ne garantit pas, que la boucle est exécutée en parallèle, on doit considérer cela comme un facultatif fonctionnalité. Par itération sur votre liste aveclist.parallelStream().forEach(...);
, vous avez explicitement le dire: Cette boucle prend en charge l'exécution en parallèle, mais il ne dépend pas d'elle. Encore une fois, c'est une fonction et non d'un déficit de!En déplaçant la décision pour l'exécution en parallèle à l'écart de votre boucle de mise en œuvre, vous permettez à l'option d'optimisation de votre code, sans affecter le code lui-même, ce qui est une bonne chose. Aussi, si le défaut courant parallèle de la mise en œuvre ne répondent pas à vos besoins, personne ne vous empêche de fournir votre propre mise en œuvre. Vous pourriez par exemple offrir une collection optimisée en fonction du sous-jacent système d'exploitation, la taille de la collection, sur le nombre de cœurs, et sur certains paramètres de préférence:
La bonne chose ici est que votre boucle de mise en œuvre n'a pas besoin de connaître ou de se soucier de ces détails.
forEach
etfor-each
en fonction de certains critères relatifs à la nature du corps de la boucle. La sagesse et la discipline de suivre ces règles sont la marque d'un bon programmeur. Ces règles sont aussi sa bane, parce que les gens autour de lui, soit ne pas les suivre ou pas d'accord. Par exemple, en utilisant vérifié vs décoché Exceptions. Cette situation semble encore plus nuancée. Mais, si le corps "n'affecte pas l'entourent code ou de contrôle de flux," n'est pas l'affacturage comme une fonction mieux?for-each
) et à l'aide de la fonction des objets (qui peut également être appelé à partir d'unfor-each
). Je ne suis pas opposé à l'une de ces techniques, et l'utilisation de la fonction des objets. Je ne suis pas sûr pourquoi ils encouragent l'utilisation deforEach()
(qui, encore une fois, ne les laissons pas utiliser checked exceptions). Oui, la syntaxe est un peu plus courte. Quelles sont les autres raisons?for-each
aller au-delà du coût d'une liste d'accès. La JVM peut se déplacer redondant évaluations d'expression, de répartir les objets sur la pile au lieu de le tas, etc, etc. C'est là que les lambdas de retard.ExecutorService
. Et il prend également des lambdas.But, if the body "does not affect surround code or flow control," isn't factoring it out as a function better?
. Oui, ce sera souvent le cas, à mon avis, en tenant compte de ces boucles de fonctions est une conséquence naturelle.Iterable#forEach
avant Java 8 seulement en raison de l'augmentation de la performance. Le projet en question a une boucle principale semblable à une boucle de jeu, avec un nombre indéterminé de imbriquée des sous-boucle, où les clients peuvent plug-in de loop participants comme des fonctions. Une telle structure logicielle de grands avantages deIteable#forEach
.+int(PI/3)
pour la Science! - strictement parlant, pour l'Étrier de référence... il a certainement prouve queforEac
h est pas un PROCESSEUR hog que considéré par beaucoup (la "idiomatiques-ness" de il & JDK 8 de la pénétration du marché [Android n'importe qui?] une autre chose).Iterable#forEach()
surpasse la traditionnelle boucle?forEach()
peut être mis en œuvre pour être plus rapide que la boucle for-each, parce que l'objet iterable sait que le meilleur moyen pour parcourir ses éléments, par opposition à la norme itérateur façon. Donc, la différence est la boucle interne ou de la boucle externe.Par exemple
ArrayList.forEach(action)
peut être simplement mis en œuvre commecontrairement à la boucle for-each, qui nécessite beaucoup d'échafaudage
Toutefois, nous devons également tenir compte de deux frais généraux en utilisant
forEach()
, on fait le lambda de l'objet, l'autre est en invoquant le lambda de la méthode. Ils ne sont probablement pas significative.voir aussi http://journal.stuffwithstuff.com/2013/01/13/iteration-inside-and-out/ pour comparer interne/externe itérations pour différents cas d'utilisation.
void forEach(Consumer<T> v){leftTree.forEach(v);v.accept(rootElem);rightTree.forEach(v);}
, c'est plus élégant que l'extérieur de l'itération, et vous pouvez décider sur la meilleure façon de synchroniserString.join
méthodes (bien, mal joindre) est "Nombre d'éléments probablement pas la peine de Tableaux.flux de charge." alors, ils utilisent une chic pour la boucle.TL;DR:
List.stream().forEach()
a été le plus rapide.J'ai senti que je dois ajouter mes résultats d'analyse comparative de l'itération.
J'ai pris une approche très simple (pas d'analyse comparative des cadres) et comparées 5 méthodes différentes:
for
List.forEach()
List.stream().forEach()
List.parallelStream().forEach
la procédure de test et les paramètres
La liste dans cette catégorie doivent être itéré et d'avoir quelques
doIt(Integer i)
appliqué à tous les membres, à chaque époque, par une méthode différente.dans la classe Principale-je exécuter la méthode éprouvée trois fois pour se réchauffer de la JVM. Je puis exécutez le test de la méthode de 1000 fois en additionnant le temps qu'il faut pour chaque itération de la méthode (à l'aide de
System.nanoTime()
). Après cela est fait, je diviser cette somme par 1000 et voilà le résultat, la moyenne du temps.exemple:
J'ai couru ce sur un i5 4 core CPU, avec la version java 1.8.0_05
classique
for
temps d'exécution: 4.21 ms
classique foreach
temps d'exécution: 5.95 ms
List.forEach()
temps d'exécution: 3.11 ms
List.stream().forEach()
temps d'exécution: 2.79 ms
List.parallelStream().forEach
temps d'exécution: 3.6 ms
System.out.println
pour afficher ces données naïvement, alors que tous les résultats sont inutiles.System.nanoTime()
. Si vous avez lu la réponse, vous allez voir comment c'était fait. Je ne pense pas que le fait qu'il est inutile vu que c'est un relative question. Je n'aime pas la façon dont une certaine méthode n', j'aime bien la manière dont il l'a fait, par rapport aux autres méthodes.Je sens que j'ai besoin de prolonger mon commentaire un peu...
Paradigme\style
C'est probablement l'aspect le plus remarquable. FP est devenu populaire en raison de ce que vous pouvez obtenir en évitant les effets secondaires. Je ne vais pas plonger en profondeur dans ce que les pros\cons que vous pouvez obtenir à partir de cela, car ce n'est pas lié à la question.
Cependant, je dirai que l'itération à l'aide de Itératif.forEach est inspiré par FP et sont plutôt le résultat d'amener plus de FP à Java (ironiquement, je dirais qu'il n'y a pas beaucoup d'utilisation de forEach dans le plus pur FP, car il ne fait rien à l'exception de l'introduction d'effets secondaires).
À la fin, je dirais que c'est plutôt une question de goût\style\paradigme que vous êtes en train d'écrire dans.
Sur le parallélisme.
Du point de vue des performances il n'y a pas promis de notables avantages de l'utilisation d'Itératif.forEach foreach(...).
Selon docs sur Itératif.forEach :
... c'est à dire docs assez bien clair qu'il n'y aura pas de parallélisme implicite. L'ajout de l'un serait LSP violation.
Maintenant, il y a "parallèle des collections" qui sont promis à Java 8, mais de travailler avec ceux que vous avez besoin de moi plus explicite et mettre un peu de soin supplémentaire pour les utiliser (voir mschenk74 de réponse par exemple).
BTW: dans ce cas Flux de données.forEach sera utilisé, et il ne garantit pas que le nombre réel de travail sera mené en parallèle (dépend de la collection sous-jacente).
Mise à JOUR: peut-être pas évident et un peu tendu en un coup d'œil, mais il est une autre facette du style et de la lisibilité de la perspective.
Tout d'abord - le bon vieux forloops sont simples et vieux. Tout le monde connaît déjà.
Deuxièmement, et plus important, vous voudrez probablement utiliser Itératif.forEach avec un seul-liner lambdas. Si le "corps" devient plus lourd, ils ont tendance à être non-lisible.
Vous avez 2 options à partir d'ici - utiliser les classes internes (beurk) ou d'utiliser un bon vieux forloop.
Les gens souvent ennuyé quand ils voient les mêmes choses (iteratins sur les collections), fait divers vays/styles dans la même base de code, et cela semble être le cas.
Encore une fois, cela pourrait ou ne pourrait pas être un problème. Dépend des gens travaillant sur le code.
collection.forEach(MyClass::loopBody);
L'un des plus upleasing fonctionnelle
forEach
's limites, c'est le manque de checked exceptions support.Un solution de contournement possible est de remplacer le terminal
forEach
par le bon vieux boucle foreach:Voici une liste des questions les plus appréciées avec d'autres solutions de contournement sur vérifié la gestion des exceptions dans les lambdas et des ruisseaux:
Java 8 fonction Lambda qui lève une exception?
Java 8: Lambda-Flux, Filtre par la Méthode à l'Exception
Comment puis-je jeter CHECKED exceptions à l'intérieur de Java 8 flux?
Java 8: Obligatoire vérifié la gestion des exceptions dans les expressions lambda. Pourquoi obligatoire, pas une option?
L'avantage de Java 1.8 méthode forEach plus de 1,7 Amélioré pour la boucle, c'est que lors de l'écriture de code, vous pouvez vous concentrer sur la logique métier seulement.
forEach méthode prend en java.util.fonction.Objet de consommation comme un argument, de sorte Il aide à avoir notre logique métier à un autre endroit que vous pouvez réutiliser à tout moment.
Avoir regarder ci-dessous l'extrait de code,
Ici, j'ai créé une nouvelle Classe qui va l'emporter accepter méthode de classe de Classe de Consommateur,
où vous pouvez ajouter d'autres functionility, Plus d'Itération..!!!!!!