我在整个编程过程中遇到的一个常见困境是在循环中声明变量。假设我必须执行以下操作:
List list=myObject.getList();
Iterator itr=list.iterator();
while (itr.hasNext()){
BusinessObject myBo=(BusinessObject)itr.next();
process(myBo);
}
在上面的代码片段中,应该在循环外声明myBo
还是在循环内声明它不会对内存和性能造成损害?
答案 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
被置于堆栈中,并且应该大部分被优化掉。您的代码不应该有任何性能损失。