简体   繁体   English

循环内的变量声明

[英]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? 在上面的代码片段中, myBo是应该在循环外声明还是在循环中声明它不会对内存和性能造成损害?

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

If possible use List<BusinessObject> and Iterator<BusinessObject> to avoid casting: 如果可能,请使用List<BusinessObject>Iterator<BusinessObject>来避免强制转换:

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()). myBo只是对对象的引用(由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. IMO,在它所使用的循环中声明它实际上有助于使其更具可读性。

The most elegant solution for your loop would be an enhanced for loop (java 5 or newer): 你的循环最优雅的解决方案是增强for循环(java 5或更新版本):

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. 但即使您提供的代码也没有性能问题,因为所有临时变量只保存对BusinessObject的引用,这非常便宜。

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] . 只需用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()stringDeclaredOutsideLoop()产生相同的六指令字节码。 stringDeclaredInsideLoop() does still win: limited scope is best . stringDeclaredInsideLoop()仍然获胜: 有限的范围是最好的

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. 但是, stringAsDirectArgument()仅在四条指令中定义操作。 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? 在C ++中,如果myBo是通过复制创建的,那么可能是一个问题,但在Java中总是使用引用,不是吗?
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. 临时引用myBo放在堆栈上,应该主要进行优化。 There shouldn't be any performance penalty in your code. 您的代码不应该有任何性能损失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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