2010-01-05 4 views
8

Un dilemme auquel j'ai été confronté tout au long de la programmation concerne la déclaration des variables dans une boucle. Dire que je dois faire quelque chose comme ce qui suit:Déclaration de variables à l'intérieur d'une boucle

List list=myObject.getList(); 
Iterator itr=list.iterator(); 
while (itr.hasNext()){ 
    BusinessObject myBo=(BusinessObject)itr.next(); 
    process(myBo); 
} 

Dans l'extrait ci-dessus, devrait myBo être déclarée en dehors de la boucle ou ne déclarant à l'intérieur de la boucle ne causer des dommages à la mémoire et la performance?

Répondre

4

myBo est simplement une référence à un objet (qui est renvoyé par itr.next()). En tant que tel, la quantité de mémoire dont il a besoin est très petite, et seulement créée une fois, et l'ajouter à l'intérieur de la boucle ne devrait pas affecter votre programme. IMO, en le déclarant dans la boucle où il est utilisé, aide réellement à le rendre plus lisible.

+0

Cette réponse est trompeuse, car elle implique que la variable de référence est allouée une fois à chaque itération, ce qui est * not * vrai. –

+0

@BlueRaja - Danny Pflughoeft: Comme je l'ai dit dans ma réponse, il s'agit simplement de créer une * référence * à un objet, sans allouer l'objet entier lui-même. C'est pourquoi la quantité de mémoire est très faible - car seuls les quelques octets nécessaires pour la référence sont tout ce qui est impliqué. – MAK

+0

Oui, je comprends; mais même cette référence (le pointeur lui-même) n'est allouée qu'une seule fois, ce qui va à l'encontre de ce que la phrase * "allouer/désallouer ne devrait pas affecter de manière significative votre programme" * est implicite. –

8

La déclaration à l'intérieur de la boucle ne causera aucun dommage à la mémoire et aux performances.

5

Si possible, utilisez List<BusinessObject> et Iterator<BusinessObject> pour éviter la coulée:

List<BusinessObject> list = myObject.getList(); 
Iterator<BusinessObject> itr = list.iterator(); 

while (itr.hasNext()) { 
    process(itr.next()); 
} 
+3

Cela ne fonctionne bien sûr qu'à partir de la version 1.5. Tout le monde n'est pas aussi chanceux :) – extraneon

5

Un principe de conception de logiciels est de limiter la portée des variables locales, à savoir les déclarer juste à temps dans un bloc qui se termine peu de temps après la dernière utilisation de cette variable. Cela n'affecte pas les performances ou d'autres aspects "durs", mais rend le programme plus lisible et plus facile à analyser. En résumé, faire ce que vous faites est considéré comme BON.

1

Si court - no. En C++ cela pourrait poser un problème si myBo est créé en copiant mais en Java il y a toujours des références utilisées, n'est-ce pas?

0

La référence temporaire myBo est placée sur la pile et doit être optimisée pour l'essentiel. Il ne devrait pas y avoir de pénalité de performance dans votre code.

4

La solution la plus élégante pour votre boucle serait une améliorée boucle (Java 5 ou plus récent):

List<BusinessObject> list = myObject.getList(); 

for(BusinessObject myBo : list) { 
    process(myBo); 
} 

Mais même avec le code pourvu qu'il n'y ait pas de problème de performance, parce que toutes les variables temporaires ne contenir que des références au BusinessObject, ce qui est très bon marché.

2

Cela ne cause aucun dommage à la mémoire.

BTW à moins que vous omettre un code que vous pouvez ignorer la déclaration tout à fait:

while (itr.hasNext()){ 
    //BusinessObject myBo=(BusinessObject)itr.next(); 
    process((BusinessObject)itr.next()); 
} 
1

Juste un coup d'oeil sur le code d'octets avec javap -c [ClassName]. Voici une classe montrant quelques exemples de variables à usage unique avec des boucles. La décharge de bytecode est pertinente dans les commentaires:

class HelloWorldLoopsAnnotated { 
    // 
    // HelloWorldLoopsAnnotated(); 
    // Code: 
    // 0: aload_0 
    // 1: invokespecial #1; //Method java/lang/Object."<init>":()V 
    // 4: return 
    //////////////////////////////////////////////////////////////////////////// 

    void stringDeclaredInsideLoop(){ 
     while (true) { 
      // 0: ldC#2; //String Hello World! 
      String greeting = "Hello World!"; 
      doNothing(greeting); 
     } 
    } 
    // 
    // void stringDeclaredInsideLoop(); 
    // Code: 
    // 0: ldC#2; //String Hello World! 
    // 2: astore_1 
    // 3: aload_0 
    // 4: aload_1 
    // 5: invokespecial #3; //Method doNothing:(Ljava/lang/String;)V 
    // 8: goto 0 
    //////////////////////////////////////////////////////////////////////////// 

    void stringDeclaredOutsideLoop(){ 
     String greeting; 
     while (true) { 
      greeting = "Hello World!"; 
      doNothing(greeting); 
     } 
    } 
    // 
    // void stringDeclaredOutsideLoop(); 
    // Code: 
    // 0: ldC#2; //String Hello World! 
    // 2: astore_1 
    // 3: aload_0 
    // 4: aload_1 
    // 5: invokespecial #3; //Method doNothing:(Ljava/lang/String;)V 
    // 8: goto 0 
    //////////////////////////////////////////////////////////////////////////// 

    void stringAsDirectArgument(){ 
     while (true) { 
      doNothing("Hello World!"); 
     } 
    } 
    // void stringAsDirectArgument(); 
    // Code: 
    // 0: aload_0 
    // 1: ldC#2; //String Hello World! 
    // 3: invokespecial #3; //Method doNothing:(Ljava/lang/String;)V 
    // 6: goto 0 
    //////////////////////////////////////////////////////////////////////////// 

    private void doNothing(String s) { 
    } 
} 

stringDeclaredInsideLoop() et stringDeclaredOutsideLoop() rendement identique bytecode six instruction. stringDeclaredInsideLoop() gagne toujours: portée limitée est le meilleur.Après quelques réflexions, je ne vois pas vraiment comment le serrage pourrait affecter les performances: des données identiques dans la pile nécessiteraient des instructions identiques.

stringAsDirectArgument(), cependant, définit l'opération dans seulement quatre instructions. Les environnements à faible mémoire (par exemple, mon téléphone magnifiquement stupide) peuvent apprécier l'optimisation alors qu'un collègue lisant votre code ne peut pas, alors exercez votre jugement avant de raser les octets de votre code.

Voir le full gist pour plus.

Questions connexes