繁体   English   中英

循环内的变量声明

[英]Variable declaration inside a loop

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

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

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

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

如果可能,请使用List<BusinessObject>Iterator<BusinessObject>来避免强制转换:

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

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

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

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

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

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

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

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

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

它不会造成任何内存伤害。

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

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

只需用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()仅在四条指令中定义操作。 低内存环境(例如我笨拙的手机)可能会欣赏优化,同时阅读代码的同事可能不会,因此在从代码中删除字节之前要做出判断。

请参阅完整要点了解更多信息。

如果短 - 没有。 在C ++中,如果myBo是通过复制创建的,那么可能是一个问题,但在Java中总是使用引用,不是吗?
为了性能,它更好地优化您在进程中所做的事情()

临时引用myBo放在堆栈上,应该主要进行优化。 您的代码不应该有任何性能损失。

暂无
暂无

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

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