45 votes

pour la boucle d'optimisation

List<String> flowers = new ArrayList<String>();

Ma boucle for actuellement ressemble à ceci...

for (int i = 0; i < flowers.size(); i++) {
...
}

OU dois-je changer pour ressembler le code donné ci-dessous

int size = flowers.size();
for (int i = 0; i < size; i++) {
...
}

Qui est plus performant (en supposant que j'ai un grand tableau de fleurs), je suppose qu'il devrait être le dernier.

57voto

Jigar Joshi Points 116533

Il est préférable d'utiliser de boucle for-each [plus lisible]

for (Flower flower :flowers){
    //...
}

J'ai largué les instructions à l'aide de javap pour le code suivant:

public void forLoop1() {
    List<String> lst = new ArrayList<String>();
    for (int i = 0; i < lst.size(); i++) {
        System.out.println("hi");
    }
}

public void forLoop2() {
    List<String> lst = new ArrayList<String>();
    int size = lst.size();
    for (int i = 0; i < size; i++) {
        System.out.println("hi");
    }
}

public void forLoop1();
  Code:
   0:   new     #2; //class java/util/ArrayList
   3:   dup
   4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   7:   astore_1
   8:   iconst_0
   9:   istore_2
   10:  iload_2
   11:  aload_1
   12:  invokeinterface #4,  1; //InterfaceMethod java/util/List.size:()I
   17:  if_icmpge       34
   20:  getstatic       #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   23:  ldc     #6; //String hi
   25:  invokevirtual   #7; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
   28:  iinc    2, 1
   31:  goto    10
   34:  return

public void forLoop2();
  Code:
   0:   new     #2; //class java/util/ArrayList
   3:   dup
   4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   7:   astore_1
   8:   aload_1
   9:   invokeinterface #4,  1; //InterfaceMethod java/util/List.size:()I
   14:  istore_2
   15:  iconst_0
   16:  istore_3
   17:  iload_3
   18:  iload_2
   19:  if_icmpge       36
   22:  getstatic       #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   25:  ldc     #6; //String hi
   27:  invokevirtual   #7; //Method java/io/PrintStream.println:(Ljava/lang/Str
ing;)V
   30:  iinc    3, 1
   33:  goto    17
   36:  return

Il n'est pas optimiser pour moi.

java version "1.6.0_22" Java(TM) SE Runtime Environment (build 1.6.0_22-b04) Java HotSpot(TM) Client VM (build 17.1-b03, en mode mixte, le partage)

Donc, si vous devez choisir mentionné deux, va pour la deuxième, mais personnellement, je aller pour for-each.


pour chaque Performance

À partir de l'Article 46 Efficace Java par Joshua Bloch :

La boucle for-each, introduit dans la version 1.5, se débarrasser de l'encombrement et la possibilité de l'erreur par masquage de l'itérateur ou variable d'index complètement. L'résultant de l'idiome s'applique également aux collections et tableaux:

// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
    doSomething(e);
}

Quand vous voyez le signe deux-points (:), la lire "en." Ainsi, la boucle ci-dessus se lit comme "pour chaque élément e dans les éléments." Note qu'il n'y a pas de perte de performance pour l'utilisation de la boucle for-each, même pour les tableaux de. En fait, il peut offrir une légère avantage de performance sur un ordinaire pour la boucle dans certaines circonstances, comme il calcule la limite de l'index de tableau qu'une seule fois. Alors que vous pouvez le faire par main (Point 45), les programmeurs ne sont pas toujours le faire.


Voir Aussi

20voto

David Titarenco Points 17148

Désolé de le dire, mais @Jigar la réponse est incorrecte. C'est la réponse correcte. (tldr; ne pas utiliser for : each).

import java.util.ArrayList;
import java.util.List;

public class LoopTest {

    public static void main(String s[]) {

        long start, end;

        List<Integer> a =  new ArrayList<Integer>();

        for (int i = 0; i < 2500000; i++) {
            a.add(i);
        }

        ///// TESTING FOR : EACH LOOP

        start = System.currentTimeMillis();

        for (Integer j : a) {
            int x = j + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ Integer j : a ] ");

        ////// TESTING DEFAULT LOOP

        start = System.currentTimeMillis();
        for (int i = 0; i < a.size(); i++) {
            int x = a.get(i) + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ int i = 0; i < a.length; i++ ] ");


        ////// TESTING SLIGHTLY OPTIMIZED LOOP

        start = System.currentTimeMillis();
        int size = a.size();
        for (int i = 0; i < size; i++) {
            int x = a.get(i) + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ int i = 0; i < size; i++ ] ");        

        //// TESTING MORE OPTIMIZED LOOP

        start = System.currentTimeMillis();
        for (int i = size; --i >= 0;) {
            int x = a.get(i) + 3;
        }

        end = System.currentTimeMillis();

        System.out.println(end - start
                + " milli seconds for [ int i = size; --i >= 0; ] ");       

    }

}

Les résultats:

96 milli seconds for [ Integer j : a ] 
57 milli seconds for [ int i = 0; i < a.length; i++ ] 
31 milli seconds for [ int i = 0; i < size; i++ ] 
31 milli seconds for [ int i = size; --i >= 0; ] 

Vous pouvez faire votre propre avis, mais trop d'attribution est donnée à la JVM de l'optimiseur. Vous avez encore d'être intelligent avec votre propre code, et à l'aide de for : each de la notation n'est PAS une bonne idée (presque jamais). Comme vous pouvez le voir, vous avez une bonne idée en mettant la taille de sa variable.

Même si certains de ces optimisation peut être JVM-dépendante (et certains peuvent le coup de pied avec le JIT), il est important de savoir ce que Java et Java ne pas le faire.

11voto

Raze Points 1304

La JVM ne peut pas optimiser car size() est une méthode, et de la JVM ne peut pas (et ne pas essayer de) déterminer que l' size() renverra toujours la même valeur dans ce contexte. Fournis size() de la valeur ne change pas, le second est un peu plus performant, mais le gain est tellement, tellement légère que vous n'avez pas vraiment à même d'envisager de l'utiliser.

9voto

Peter Lawrey Points 229686

Si la performance est critique, utilisez la plaine de compteur de boucle, mais pour 98% des cas, la clarté et la simplicité de code est beaucoup plus important (comme 1000x ou plus) et vous devez utiliser une boucle for-each.

@David souligne que l'utilisation d'un compteur est plus rapide, mais je tiens à souligner que, même pour 10 000 entrées, la différence est inférieure à la microseconde.

Si vous avez une collection de plus de 10 000 entrées, il est très probable que vous ne devriez pas être la force brute itération sur toutes les possibilités. Il est plus probable une collection avec une recherche comme une Carte est une meilleure solution pour ce que vous avez à l'esprit. Si vous avez beaucoup moins de 10 000 entrées de la performance est moins susceptible d'être important.

4voto

Andreas_D Points 64111

De la Java language specification (14.14.1):

La base pour l'instruction exécute du code d'initialisation, puis exécute une Expression, une Déclaration, et certains code de mise à jour à plusieurs reprises jusqu'à ce que la valeur de la L'Expression est fausse.

L'Expression est - i < flowers.size() dans votre premier exemple et c'est évaluée une fois à chaque itération. Dans votre cas particulier, il ne devrait pas faire une différence non négligeable, car flowers.getSize() sur ArrayList est très peu de méthode. Mais, en général, si le résultat de l'expression est la même pour chaque itération et cher, ensuite faire une pré-calcul.

Conséquence: cela doit produire le même résultat à chaque mise en œuvre d'une machine virtuelle Java et prouve, que l'Expression est d'évaluer une fois à chaque itération:

int counter2 = 10;
for (int counter1 = 0; counter1 < counter2; counter1++) {
  System.out.println(counter1 + ", " + counter2);
  counter2--;
}

Sortie:

0, 10
1, 9
2, 8
3, 7
4, 6

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X