简体   繁体   中英

Variable declaration inside a loop

One common dilemma I have faced throughout programming is regarding declaring variables inside a loop. Say I have to perform something like the following:

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

In the above snippet, should myBo be declared outside the loop or does declaring it inside the loop not cause harm to memory and performance?

在循环内声明它不会对内存和性能造成任何损害。

If possible use List<BusinessObject> and Iterator<BusinessObject> to avoid casting:

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

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

One principle of good software design is to limit the scope of local variables, ie to declare them just in time within a block that ends soon after the last use of that variable. This doesn't affect performance or other "hard" aspects but makes the program more readable and easier to analyze.

In summary, doing what you're doing is considered GOOD.

myBo is simply a reference to an object (that is returned by itr.next()). As such the amount of memory that it needs is very small, and only created once, and adding it inside the loop should not affect your program. IMO, declaring it inside the loop where it is used actually helps make it more readable.

The most elegant solution for your loop would be an enhanced for loop (java 5 or newer):

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

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

But even with the code you provided there will be no performance problem, because all the temporary variables only hold references to the BusinessObject , which is very cheap.

It doesn't cause any memory harm.

BTW unless you're omitting some code you may skip the declaration altogether:

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

Just have a look at the byte code with javap -c [ClassName] . Here's a class demonstrating a few examples of single-use variables with loops. The relevant bytecode dump is in the comments:

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() and stringDeclaredOutsideLoop() yield identical six-instruction bytecode. stringDeclaredInsideLoop() does still win: limited scope is best .

After some contemplation, I can't really see how tightening scope would ever affect performance: identical data in the stack would necessitate identical instructions.

stringAsDirectArgument() , however, defines the operation in only four instructions. Low memory environments (eg my magnificently dumb phone) may appreciate the optimization while a colleague reading your code may not, so exercise judgement before shaving bytes from your code.

See the full gist for more.

If short -- no. In C++ it could be a problem if myBo is created by copying but in Java there is always used references, is'nt it?
for performance, its better to optimize something you are do in process()

The temporary reference myBo is put on stack and should mostly be optimized away. There shouldn't be any performance penalty in your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM