Lorsque j'itère une collection en utilisant le nouveau sucre syntaxique de Java 8, tel que
myStream.forEach(item -> {
// do something useful
});
N'est-ce pas équivalent à l'extrait de code «ancienne syntaxe» ci-dessous?
myStream.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
// do something useful
}
});
Cela signifie-t-il qu'un nouvel Consumer
objet anonyme est créé sur le tas chaque fois que j'itère sur une collection? Combien d'espace de tas cela prend-il? Quelles implications en termes de performances cela a-t-il? Cela signifie-t-il que je devrais plutôt utiliser l'ancien style pour les boucles lors de l'itération sur de grandes structures de données à plusieurs niveaux?
Réponses:
C'est équivalent mais pas identique. Simplement dit, si une expression lambda ne capture pas de valeurs, ce sera un singleton qui est réutilisé à chaque appel.
Le comportement n'est pas exactement spécifié. La JVM a une grande liberté sur la façon de l'implémenter. Actuellement, la JVM d'Oracle crée (au moins) une instance par expression lambda (c'est-à-dire ne partage pas d'instance entre différentes expressions identiques) mais crée des singletons pour toutes les expressions qui ne capturent pas de valeurs.
Vous pouvez lire cette réponse pour plus de détails. Là, j'ai non seulement donné une description plus détaillée, mais aussi tester le code pour observer le comportement actuel.
Ceci est couvert par la spécification du langage Java®, chapitre « 15.27.4. Évaluation d'exécution des expressions Lambda »
Résumé:
la source
La création d'une instance représentant le lambda dépend du contenu exact du corps de votre lambda. À savoir, le facteur clé est ce que le lambda capture de l'environnement lexical. S'il ne capture aucun état variable de la création à la création, alors une instance ne sera pas créée à chaque fois que la boucle for-each est entrée. Au lieu de cela, une méthode synthétique sera générée au moment de la compilation et le site d'utilisation lambda recevra simplement un objet singleton qui délègue à cette méthode.
Notez en outre que cet aspect dépend de la mise en œuvre et que vous pouvez vous attendre à des améliorations et des progrès futurs sur HotSpot vers une plus grande efficacité. Il existe des plans généraux pour, par exemple, créer un objet léger sans classe correspondante complète, qui a juste assez d'informations pour être transmis à une seule méthode.
Voici un bon article en profondeur accessible sur le sujet:
http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
la source
Vous transmettez une nouvelle instance à la
forEach
méthode. Chaque fois que vous faites cela, vous créez un nouvel objet mais pas un pour chaque itération de boucle. L'itération est effectuée à l'intérieur de laforEach
méthode en utilisant la même instance d'objet 'callback' jusqu'à ce qu'elle soit faite avec la boucle.Ainsi, la mémoire utilisée par la boucle ne dépend pas de la taille de la collection.
Oui. Il y a de légères différences à un niveau très bas, mais je ne pense pas que vous devriez vous en soucier. Les expressions Lamba utilisent la fonctionnalité invokedynamic au lieu des classes anonymes.
la source