En supposant que j'ai une ArrayList
ArrayList<MyClass> myList;
Et je veux appeler toArray, y a-t-il une raison de performance à utiliser
MyClass[] arr = myList.toArray(new MyClass[myList.size()]);
plus de
MyClass[] arr = myList.toArray(new MyClass[0]);
?
Je préfère le deuxième style, car il est moins verbeux, et j'ai supposé que le compilateur s'assurait que le tableau vide ne soit pas vraiment créé, mais je me suis demandé si c'était vrai.
Bien sûr, dans 99% des cas, cela ne fait aucune différence dans un sens ou dans l'autre, mais j'aimerais garder un style cohérent entre mon code normal et mes boucles internes optimisées ...
java
performance
coding-style
Itsadok
la source
la source
Réponses:
Contre-intuitivement, la version la plus rapide, sur Hotspot 8, est:
J'ai exécuté un micro-benchmark en utilisant jmh, les résultats et le code sont ci-dessous, montrant que la version avec un tableau vide surpasse systématiquement la version avec un tableau prédéfini. Notez que si vous pouvez réutiliser un tableau existant de la taille correcte, le résultat peut être différent.
Résultats de référence (score en microsecondes, plus petit = meilleur):
Pour référence, le code:
Vous pouvez trouver des résultats similaires, une analyse complète et une discussion dans le billet de blog Arrays of Wisdom of the Ancients . Pour résumer: le compilateur JVM et JIT contient plusieurs optimisations qui lui permettent de créer et d'initialiser à moindre coût un nouveau tableau correctement dimensionné, et ces optimisations ne peuvent pas être utilisées si vous créez le tableau vous-même.
la source
MyClass[] arr = myList.stream().toArray(MyClass[]::new);
.. ce qui, je suppose, serait plus lent. Aussi, je voudrais voir des points de repère pour la différence avec la déclaration de tableau. Comme dans la différence entre:MyClass[] arr = new MyClass[myList.size()]; arr = myList.toArray(arr);
etMyClass[] arr = myList.toArray(new MyClass[myList.size()]);
... ou ne devrait-il pas y avoir de différence? Je suppose que ces deux problèmes sont en dehors destoArray
événements fonctionnels. Mais salut! Je ne pensais pas que j'apprendrais les autres différences complexes.toArray
directement (plus la taille est petite, plus la surcharge relative est grande)À partir de ArrayList dans Java 5 , le tableau sera déjà rempli s'il a la bonne taille (ou est plus grand). par conséquent
va créer un objet tableau, le remplir et le renvoyer à "arr". D'autre part
créera deux tableaux. Le second est un tableau de MyClass de longueur 0. Il y a donc une création d'objet pour un objet qui sera immédiatement jeté. Pour autant que le code source le suggère, le compilateur / JIT ne peut pas optimiser celui-ci pour qu'il ne soit pas créé. En outre, l'utilisation de l'objet de longueur nulle entraîne des transtypages dans la méthode toArray ().
Voir la source de ArrayList.toArray ():
Utilisez la première méthode pour qu'un seul objet soit créé et évitez les castings (implicites mais néanmoins coûteux).
la source
new Myclass[0]
c'est plus rapide: shipilev.net/blog/2016/arrays-wisdom-ancientsÀ partir de l'inspection JetBrains Intellij Idea:
la source
Les JVM modernes optimisent la construction de la matrice réfléchissante dans ce cas, donc la différence de performances est minime. Nommer la collection deux fois dans un tel code standard n'est pas une bonne idée, alors j'éviterais la première méthode. Un autre avantage du second est qu'il fonctionne avec des collections synchronisées et simultanées. Si vous souhaitez faire une optimisation, réutilisez le tableau vide (les tableaux vides sont immuables et peuvent être partagés), ou utilisez un profileur (!).
la source
private static final MyClass[] EMPTY_MY_CLASS_ARRAY = new MyClass[0]
n'empêche pas le tableau retourné d'être construit par la réflexion, mais il n'empêcher un tableau supplémentaire construit chaque à chaque fois.MyClass[] arr = myList.stream().toArray(MyClass[]::new);
cela aiderait ou ferait-il mal avec les collections synchronisées et simultanées. Et pourquoi? S'il vous plaît.toArray vérifie que le tableau passé est de la bonne taille (c'est-à-dire suffisamment grand pour contenir les éléments de votre liste) et si c'est le cas, l'utilise. Par conséquent, si la taille du tableau le fournissait plus petite que nécessaire, un nouveau tableau sera créé par réflexe.
Dans votre cas, un tableau de taille zéro est immuable et peut donc être élevé en toute sécurité à une variable finale statique, ce qui pourrait rendre votre code un peu plus propre, ce qui évite de créer le tableau à chaque appel. Un nouveau tableau sera de toute façon créé à l'intérieur de la méthode, c'est donc une optimisation de la lisibilité.
La version la plus rapide consiste sans doute à transmettre le tableau d'une taille correcte, mais à moins que vous ne puissiez prouver que ce code est un goulot d'étranglement des performances, préférez la lisibilité aux performances d'exécution jusqu'à preuve du contraire.
la source
Le premier cas est plus efficace.
En effet, dans le second cas:
le runtime crée en fait un tableau vide (avec une taille nulle), puis à l'intérieur de la méthode toArray crée un autre tableau pour s'adapter aux données réelles. Cette création se fait en utilisant la réflexion en utilisant le code suivant (extrait de jdk1.5.0_10):
En utilisant le premier formulaire, vous évitez la création d'un deuxième tableau et évitez également le code de réflexion.
la source
Le second est légèrement plus lisible, mais il y a si peu d'amélioration que cela n'en vaut pas la peine. La première méthode est plus rapide, sans inconvénient à l'exécution, c'est donc ce que j'utilise. Mais je l'écris de la deuxième façon, car c'est plus rapide à taper. Ensuite, mon IDE le signale comme un avertissement et propose de le réparer. D'une simple pression sur une touche, il convertit le code du deuxième type au premier.
la source
L'utilisation de 'toArray' avec le tableau de la taille correcte fonctionnera mieux car l'alternative créera d'abord le tableau de taille zéro, puis le tableau de la taille correcte. Cependant, comme vous le dites, la différence sera probablement négligeable.
Notez également que le compilateur javac n'effectue aucune optimisation. De nos jours, toutes les optimisations sont effectuées par les compilateurs JIT / HotSpot lors de l'exécution. Je n'ai connaissance d'aucune optimisation autour de «toArray» dans les machines virtuelles Java.
La réponse à votre question est donc en grande partie une question de style, mais par souci de cohérence, elle doit faire partie de toutes les normes de codage auxquelles vous adhérez (qu'elles soient documentées ou non).
la source
exemple de code pour entier:
la source