Java foreach efficacité
J'ai quelque chose comme ceci:
Map<String, String> myMap = ...;
for(String key : myMap.keySet()) {
System.out.println(key);
System.out.println(myMap.get(key));
}
Donc myMap.keySet()
est-il appelé une fois dans la boucle foreach ?
Je pense que c'est, mais que vous voulez de votre avis.
Je voudrais savoir si l'utilisation de foreach de cette manière (myMap.keySet()
) a un impact sur les performances ou est équivalente à ceci:
Set<String> keySet = myMap.keySet();
for (String key : keySet) {
...
}
6 réponses
Si vous voulez être absolument certain, compilez-le dans les deux sens et décompilez-le et comparez-le. Je l'ai fait avec la source suivante:
public void test() {
Map<String, String> myMap = new HashMap<String, String>();
for (String key : myMap.keySet()) {
System.out.println(key);
System.out.println(myMap.get(key));
}
Set<String> keySet = myMap.keySet();
for (String key : keySet) {
System.out.println(key);
System.out.println(myMap.get(key));
}
}
Et quand j'ai décompilé le fichier de classe avec Jad, j'obtient:
public void test()
{
Map myMap = new HashMap();
String key;
for(Iterator iterator = myMap.keySet().iterator(); iterator.hasNext(); System.out.println((String)myMap.get(key)))
{
key = (String)iterator.next();
System.out.println(key);
}
Set keySet = myMap.keySet();
String key;
for(Iterator iterator1 = keySet.iterator(); iterator1.hasNext(); System.out.println((String)myMap.get(key)))
{
key = (String)iterator1.next();
System.out.println(key);
}
}
Voilà ta réponse. Il est appelé une fois avec la forme for-loop.
Il n'est appelé qu'une seule fois. En fait, il utilise un itérateur pour faire l'affaire.
De plus, dans votre cas, je pense que vous devriez utiliser
for (Map.Entry<String, String> entry : myMap.entrySet())
{
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
Pour éviter de chercher dans la carte à chaque fois.
keySet()
est appelé une seule fois. La "boucle for améliorée" est basée sur l'interface Iterable
, qu'elle utilise pour obtenir un Iterator
, qui est ensuite utilisé pour la boucle. Il n'est même pas possible d'itérer sur un Set
d'une autre manière, car il n'y a pas d'index ou quoi que ce soit par lequel vous pourriez obtenir des éléments individuels.
Cependant, ce que vous devriez vraiment faire est d'abandonner complètement ce genre de soucis de micro-optimisation-si jamais vous avez de vrais problèmes de performance, la chance est d'environ 99% que c'est une chose à laquelle tu n'avais jamais pensé toute seule.
La réponse est dans la spécification du langage Java, pas besoin de décompiler:) C'est ce que nous pouvons lire à propos de l'instruction enhanced for :
L'renforcée pour l'instruction a forme:
EnhancedForStatement: for ( VariableModifiersopt Type Identifier: Expression) Statement
L'Expression doit soit avoir le type
Iterable
ou bien il doit être d'un type de tableau (§10.1), ou une compilation erreur se produit.La portée d'une variable locale déclarée dans la partie FormalParameter d'un déclaration
for
améliorée (§14.14) être la déclaration contenueLa signification de l'amélioration
for
déclaration est donnée par traduction en une instruction de basefor
.Si le type de
Expression
est un sous-type deIterable
, puis laissezI
être le type de l'expression Expression.iterator()
. L'instructionfor
améliorée est équivalente à une instruction de basefor
du forme:for (I #i = Expression.iterator(); #i.hasNext(); ) { VariableModifiersopt Type Identifier = #i.next(); Statement }
Où
#i
est généré par le compilateur identificateur distinct de tout autres identifiants (générés par le compilateur ou autrement) qui sont dans le champ d'application (§6.3) au point où le amélioré pour déclaration se produit.Sinon, l'Expression nécessairement a un type de tableau,
T[]
. LaissezL1 ... Lm
être (éventuellement vide) de la séquence de étiquettes précédant immédiatement le instructionfor
améliorée. Puis le sens de l'amélioration de l'énoncé est donné par la basefor
déclaration:T[] a = Expression; L1: L2: ... Lm: for (int i = 0; i < a.length; i++) { VariableModifiersopt Type Identifier = a[i]; Statement }
Où un et , je sont générées par le compilateur identificateurs qui sont distincts de tout autres identifiants (générés par le compilateur ou autrement) qui sont dans le champ d'application à l' point où la déclaration enhanced for produire.
Dans votre cas, myMap.keySet()
renvoie un sous-type de Iterable
de sorte que votre instruction for
améliorée est équivalente à l'instruction for
de base suivante:
for (Iterator<String> iterator = myMap.keySet().iterator(); iterator.hasNext();) {
String key = iterator.next();
System.out.println(key);
System.out.println(myMap.get(key));
}
Et myMap.keySet()
ne sont ainsi appelés qu'une seule fois.
Je crois que c'est un compilateur optimisé pour ne s'exécuter qu'une seule fois par entrée de boucle.