2010-01-05 19 views
8

Ein häufiges Dilemma, mit dem ich während der Programmierung konfrontiert wurde, betrifft die Deklaration von Variablen innerhalb einer Schleife. Sagen, dass ich so etwas wie die folgenden zu erfüllen haben:Variablendeklaration innerhalb einer Schleife

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

In dem obigen Schnipsel sollte myBo außerhalb der Schleife deklariert werden oder es innerhalb der Schleife nicht erklärt, keine schädlichen Auswirkungen auf Speicher und Leistung führen?

Antwort

4

myBo ist einfach eine Referenz auf ein Objekt (das von itr.next() zurückgegeben wird). Daher ist die Menge an Speicher, die benötigt wird, sehr klein und wird nur einmal erstellt, und das Hinzufügen innerhalb der Schleife sollte Ihr Programm nicht beeinträchtigen. IMO, erklärt es innerhalb der Schleife, wo es verwendet wird, tatsächlich hilft es lesbarer zu machen.

+0

Diese Antwort ist irreführend, da es bedeutet, dass die Referenzvariable einmal bei jeder Iteration zugeordnet wird, was * nicht * wahr ist. –

+0

@BlueRaja - Danny Pflughoeft: Wie ich in meiner Antwort gesagt habe, ist es lediglich eine * Referenz * auf ein Objekt zu erstellen, nicht das ganze Objekt selbst zuzuordnen. Deshalb ist die Menge an Speicher sehr klein - weil nur die wenigen Bytes, die für die Referenz benötigt werden, beteiligt sind. – MAK

+0

Ja, ich verstehe; aber selbst diese Referenz (der Zeiger selbst) wird nur einmal zugewiesen, was im Gegensatz zu dem steht, was die Phrase * "Zuweisung/Freigabe der Zuweisung sollte Ihr Programm nicht signifikant beeinflussen" * impliziert. –

8

Die Deklaration innerhalb der Schleife wird den Speicher und die Leistung nicht beeinträchtigen.

5

Verwenden Sie möglichst List<BusinessObject> und Iterator<BusinessObject> Gießen zu vermeiden:

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

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

Das funktioniert natürlich nur in 1.5 und höher. Nicht jeder ist so glücklich :) – extraneon

5

Ein Prinzip der guten Software-Design ist es, den Umfang der lokalen Variablen zu begrenzen, dh sie gerade rechtzeitig zu erklären, innerhalb eines Blocks, die bald endet nach die letzte Verwendung dieser Variable. Dies beeinträchtigt nicht die Leistung oder andere "harte" Aspekte, macht das Programm jedoch lesbarer und einfacher zu analysieren.

Zusammengefasst ist das, was Sie tun, als GUT angesehen.

1

Wenn kurz - nein. In C++ kann es ein Problem sein, wenn myBo durch Kopieren erstellt wird, aber in Java gibt es immer verwendete Referenzen, nicht wahr?
für die Leistung, ist es besser, etwas zu optimieren Sie tun in Prozess()

0

Die temporäre Referenz myBo ist auf Stapel gelegt und sollte meist weg optimiert werden. Es sollte keine Leistungseinbußen in Ihrem Code geben.

4

Die eleganteste Lösung für Ihre Schleife würde eine for-Schleife (Java 5 oder neuer) erweitert:

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

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

Aber auch mit dem Code, den Sie zur Verfügung gestellt, wird kein Leistungsproblem, weil alle temporären Variablen Halten Sie nur Referenzen auf die BusinessObject, die sehr billig ist.

2

Es verursacht keinen Speicherschaden.

BTW, wenn Sie einige Code sind Weglassen können Sie die Erklärung vollständig überspringen:

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

haben Sie einen Blick auf die Byte-Code mit javap -c [ClassName]. Hier ist eine Klasse, die einige Beispiele von Variablen für den Einmalgebrauch mit Schleifen zeigt. Das entsprechende Bytecode-Dump ist in den Kommentaren:

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() und stringDeclaredOutsideLoop() Ausbeute identisch sechs Anweisung Bytecode. stringDeclaredInsideLoop() gewinnt immer noch: begrenzten Bereich ist am besten.

Nach einigem Nachdenken kann ich nicht wirklich sehen, wie verkleinerte Umfang Leistung jemals beeinflussen würde: identische Daten im Stapel würden identische Anweisungen erfordern.

stringAsDirectArgument() definiert jedoch die Operation in nur vier Anweisungen. Umgebungen mit wenig Arbeitsspeicher (z. B. mein prächtig dummes Telefon) mögen die Optimierung zu schätzen wissen, während ein Kollege, der Ihren Code liest, dies möglicherweise nicht tut, also üben Sie vor dem Rasieren von Bytes aus Ihrem Code ein Urteil.

Weitere Informationen finden Sie unter .