2009-06-17 6 views
24

En Java, est-il plus rapide à parcourir un tableau de la manière ancienne,moyen le plus rapide pour itérer un tableau en Java: variable boucle vs améliorée pour la déclaration

for (int i = 0; i < a.length; i++) 
    f(a[i]); 

Ou en utilisant la forme plus concise,

for (Foo foo : a) 
    f(foo); 

Pour une ArrayList, la réponse est-elle la même?

Bien sûr, pour la grande majorité du code d'application, la réponse est qu'elle ne fait aucune différence perceptible, de sorte que la forme la plus concise devrait être utilisée pour la lisibilité. Cependant, le contexte que je regarde est un calcul technique robuste, avec des opérations qui doivent être effectuées des milliards de fois, donc même une différence de vitesse minuscule pourrait finir par être significative.

+0

Pourquoi pas une référence? Beaucoup plus précis qu'une discussion. – Deestan

+0

Il est peu probable que vous remarquiez la différence à moins que 'f()' ne disparaisse. – EJP

+0

Cela a été [demandé avant] (http://stackoverflow.com/questions/256859/is-there-a-performance-difference-between-a-for-loop-and-a-for-each-loop). – RichardOD

Répondre

53

Si vous parcourez un tableau en boucle, cela ne devrait pas avoir d'importance - la boucle for enhanced utilise des accès au tableau de toute façon.

Par exemple, considérez ce code:

public static void main(String[] args) 
{ 
    for (String x : args) 
    { 
     System.out.println(x); 
    } 
} 

Quand décompilé avec javap -c Test nous obtenons (pour la méthode main):

public static void main(java.lang.String[]); 
    Code: 
    0: aload_0 
    1: astore_1 
    2: aload_1 
    3: arraylength 
    4: istore_2 
    5: iconst_0 
    6: istore_3 
    7: iload_3 
    8: iload_2 
    9: if_icmpge 31 
    12: aload_1 
    13: iload_3 
    14: aaload 
    15: astore 4 
    17: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 
    20: aload 4 
    22: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    25: iinc 3, 1 
    28: goto 7 
    31: return 

changer maintenant à utiliser un accès au tableau explicite:

public static void main(String[] args) 
{ 
    for (int i = 0; i < args.length; i++) 
    { 
     System.out.println(args[i]); 
    } 
} 

Cette décompile à:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_0 
    1: istore_1 
    2: iload_1 
    3: aload_0 
    4: arraylength 
    5: if_icmpge 23 
    8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 
    11: aload_0 
    12: iload_1 
    13: aaload 
    14: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    17: iinc 1, 1 
    20: goto 2 
    23: return 

Il existe un peu plus de code d'installation dans la boucle enhanced for, mais ils font essentiellement la même chose. Aucun itérateur n'est impliqué. En outre, je m'attendrais à ce qu'ils soient passés à un code encore plus similaire.Suggestion: si vous pensez vraiment que cela pourrait faire une différence significative (ce que fera jamais si le corps de la boucle est absolument minuscule) alors vous devriez le référencer avec votre vraie application. C'est la seule situation qui compte.

21

Ceci tombe carrément dans l'arène de micro-optimization. Cela n'a vraiment pas d'importance. Stylistiquement, je préfère toujours le second parce que c'est plus concis, à moins que vous ayez besoin du compteur de boucle pour autre chose. Et c'est beaucoup plus important que ce type de micro-optimisation: lisibilité. Ceci étant dit, pour une ArrayList il n'y aura pas beaucoup de différence mais une LinkedList sera beaucoup plus efficace avec la seconde.

+4

Il n'utilisera pas d'itérateur pour un tableau. –

+1

le premier style est limité à un nombre entier d'itérations, alors que le second ne l'est pas. – Chii

+2

La seconde est également limitée de cette façon car les tableaux ont un nombre d'éléments Integer.MAX_VALUE max et une ArrayList est soutenue par un tableau. – cletus

6

Mesurez-le. La réponse à toutes les questions de performance peut dépendre de la version de la VM, du processeur, de la vitesse de la mémoire, des caches, etc. Vous devez donc la mesurer pour votre plate-forme particulière.

Personnellement, je préférerais la deuxième variante, car l'intention est plus claire. Si la performance devient un problème, je peux l'optimiser plus tard de toute façon - si ce code est vraiment important pour la performance de l'ensemble de l'application.

1

Sur un tableau, ou d'une collection RandomAccess vous pouvez obtenir une petite augmentation de la vitesse en faisant:

List<Object> list = new ArrayList<Object>(); 

for (int i=0, d=list.size(); i<d; i++) { 
    something(list.get(i)); 
} 

Mais je ne vous inquiétez pas, en général. Les optimisations comme celle-ci ne feront pas plus de 0,1% de différence avec votre code. Essayez d'appeler Java avec -prof pour voir où votre code passe réellement son temps.

0

Encore plus rapide est d'utiliser le ParallelArray de l'infrastructure fork-join (si vous avez un jeu de données assez grand).

Questions connexes