循环内的变量声明

时间:2010-01-05 08:59:16

标签: java

我在整个编程过程中遇到的一个常见困境是在循环中声明变量。假设我必须执行以下操作:

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

在上面的代码片段中,应该在循环外声明myBo还是在循环内声明它不会对内存和性能造成损害?

9 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:5)

如果可能,请使用List<BusinessObject>Iterator<BusinessObject>来避免投射:

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

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

答案 2 :(得分:5)

良好软件设计的一个原则是限制局部变量的范围,即在最后一次使用该变量后不久结束的块内及时声明它们。这不会影响性能或其他“硬”方面,但会使程序更易读,更易于分析。

总之,做你正在做的事情被认为是好的。

答案 3 :(得分:4)

myBo只是对对象的引用(由itr.next()返回)。因此,它所需的内存量非常小,并且只创建一次,并且在循环内添加它不应该影响您的程序。 IMO,在使用它的循环中声明它实际上有助于使其更具可读性。

答案 4 :(得分:4)

循环最优雅的解决方案是增强for循环(java 5或更新版本):

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

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

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

答案 5 :(得分:2)

它不会造成任何记忆伤害。

除非您省略某些代码,否则您可以完全跳过声明:

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

答案 6 :(得分:1)

如果短 - 没有。 在C ++中,如果通过复制创建myBo,则可能会出现问题 但在Java中总是使用引用,不是吗? 为了提高性能,最好优化你在进程中做的事情()

答案 7 :(得分:1)

只需查看javap -c [ClassName]的字节代码即可。这是一个演示一些带循环的一次性变量示例的类。相关的字节码转储在注释中:

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()stringDeclaredOutsideLoop()产生相同的六指令字节码。 stringDeclaredInsideLoop()仍然赢了:有限的范围是最好的

经过一番思考之后,我无法真正看到范围会如何影响性能:堆栈中相同的数据需要相同的指令。

但是,

stringAsDirectArgument()仅在四条指令中定义了操作。低内存环境(例如,我极其笨拙的手机)可能会欣赏优化,同时阅读代码的同事可能不会,所以在从代码中删除字节之前进行判断。

有关详情,请参阅full gist

答案 8 :(得分:0)

临时引用myBo被置于堆栈中,并且应该大部分被优化掉。您的代码不应该有任何性能损失。