TL;DR : List.stream().forEach()
était le plus rapide.
J'ai pensé que je devais ajouter mes résultats de l'itération de benchmarking. J'ai adopté une approche très simple (pas de cadres d'évaluation comparative) et j'ai évalué 5 méthodes différentes :
- classique
for
- foreach classique
List.forEach()
List.stream().forEach()
List.parallelStream().forEach
la procédure et les paramètres d'essai
private List<Integer> list;
private final int size = 1_000_000;
public MyClass(){
list = new ArrayList<>();
Random rand = new Random();
for (int i = 0; i < size; ++i) {
list.add(rand.nextInt(size * 50));
}
}
private void doIt(Integer i) {
i *= 2; //so it won't get JITed out
}
La liste de cette classe doit être itérée et avoir une certaine doIt(Integer i)
appliqué à tous ses membres, chaque fois par une méthode différente. Dans la classe Main, j'exécute la méthode testée trois fois pour chauffer la JVM. J'exécute ensuite la méthode testée 1000 fois en additionnant le temps nécessaire pour chaque méthode d'itération (en utilisant la fonction System.nanoTime()
). Après cela, je divise cette somme par 1000 et c'est le résultat, le temps moyen. exemple :
myClass.fored();
myClass.fored();
myClass.fored();
for (int i = 0; i < reps; ++i) {
begin = System.nanoTime();
myClass.fored();
end = System.nanoTime();
nanoSum += end - begin;
}
System.out.println(nanoSum / reps);
Je l'ai exécuté sur un processeur i5 à 4 cœurs, avec la version 1.8.0_05 de java.
classique for
for(int i = 0, l = list.size(); i < l; ++i) {
doIt(list.get(i));
}
temps d'exécution : 4,21 ms
foreach classique
for(Integer i : list) {
doIt(i);
}
temps d'exécution : 5,95 ms
List.forEach()
list.forEach((i) -> doIt(i));
temps d'exécution : 3,11 ms
List.stream().forEach()
list.stream().forEach((i) -> doIt(i));
temps d'exécution : 2,79 ms
List.parallelStream().forEach
list.parallelStream().forEach((i) -> doIt(i));
temps d'exécution : 3,6 ms
0 votes
Je crois que les lamdas sont destinés à améliorer l'utilisation des processeurs multi-cœurs. Si votre environnement cible est multi-core, je pense que les lamdas auront des performances améliorées par rapport à la boucle for de java 7.
15 votes
Il n'y a pas de réel avantage en termes de performances d'un système par rapport à un autre. La première option est quelque chose qui s'inspire de la FP (dont on parle généralement comme d'une manière plus "agréable" et "claire" d'exprimer votre code). En réalité, il s'agit plutôt d'une question de "style".
5 votes
@Dwb : dans ce cas, ce n'est pas pertinent. forEach n'est pas défini comme étant parallèle ou quelque chose comme ça, donc ces deux choses sont sémantiquement équivalentes. Bien sûr, il est possible d'implémenter une version parallèle de forEach (et il se peut qu'elle soit déjà présente dans la bibliothèque standard), et dans ce cas, la syntaxe des expressions lambda serait très utile.
9 votes
@AardvarkSoup L'instance sur laquelle forEach est appelé est un Stream ( lambdadoc.net/api/java/utilitaire/stream/Stream.html ). Pour demander une exécution parallèle, on pourrait écrire joins.parallel().forEach(...)
14 votes
Est
joins.forEach((join) -> mIrc.join(mSession, join));
vraiment une "simplification" defor (String join : joins) { mIrc.join(mSession, join); }
? Vous avez fait passer le nombre de ponctuations de 9 à 12, afin de masquer le type dejoin
. Ce que vous avez fait, c'est mettre deux déclarations sur une seule ligne.1 votes
La parenthèse n'est pas nécessaire autour du côté gauche de la lambda. On pourrait donc écrire : joins.forEach( join -> mIrc.join(mSession,join) ;
1 votes
Question connexe : stackoverflow.com/questions/23218874/
9 votes
Un autre point à prendre en compte est la capacité limitée de capture de variables de Java. Avec Stream.forEach(), vous ne pouvez pas mettre à jour les variables locales puisque leur capture les rend finales, ce qui signifie que vous pouvez avoir un comportement d'état dans le lambda forEach (à moins que vous ne soyez prêt à une certaine laideur comme l'utilisation de variables d'état de classe).
0 votes
Dépend du cas d'utilisation.
0 votes
Si vous avez besoin d'une programmation parallèle, utilisez des flux, sinon, utilisez simplement l'approche triviale.
1 votes
La mise en œuvre du parallélisme sans le besoin adéquat entraînera des frais généraux excessifs.