为什么下面的代码可以正常工作?
String str;
while (condition) {
str = calculateStr();
.....
}但是这个据说是危险的/不正确的:
while (condition) {
String str = calculateStr();
.....
}是否有必要在循环外声明变量?
发布于 2012-01-10 21:12:14
局部变量的作用域应该总是尽可能小。
在您的示例中,我假设str没有在while循环之外使用,否则您就不会问这个问题,因为在while循环中声明它是不可行的,因为它不会编译。
因此,由于没有在循环外部使用str,因此str的最小作用域是在while循环内。
因此,答案是绝对应该在while循环中声明str。没有如果,没有ands,没有但是。
可能违反此规则的唯一情况是,由于某些原因,必须将每个时钟周期挤出代码,这一点至关重要,在这种情况下,您可能希望考虑实例化外部作用域中的某些内容并重用它,而不是在内部作用域的每次迭代中重新实例化它。然而,这并不适用于您的示例,因为java中字符串的不可变性: str的新实例总是会在循环的开始处创建,并且必须在循环结束时将其丢弃,因此不可能在那里进行优化。
编辑:(在答案中插入我的评论)
在任何情况下,正确的做法是正确地编写所有代码,为您的产品建立一个性能需求,根据这个需求来衡量您的最终产品,如果它不能满足它,那么就去优化它。通常最终发生的是,你找到了一些方法,在几个地方提供一些好的和正式的算法优化,使我们的程序满足其性能要求,而不是不得不遍历整个代码库,调整和修改东西,以便在这里和那里压缩时钟周期。
发布于 2012-01-16 17:39:49
我比较了这两个(类似)示例的字节代码:
让我们看一下1. 示例
package inside;
public class Test {
public static void main(String[] args) {
while(true){
String str = String.valueOf(System.currentTimeMillis());
System.out.println(str);
}
}
}在使用javac Test.java、javap -c Test之后,您将获得:
public class inside.Test extends java.lang.Object{
public inside.Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
3: invokestatic #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
6: astore_1
7: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
10: aload_1
11: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: goto 0
}让我们看一下2.示例
package outside;
public class Test {
public static void main(String[] args) {
String str;
while(true){
str = String.valueOf(System.currentTimeMillis());
System.out.println(str);
}
}
}在使用javac Test.java、javap -c Test之后,您将获得:
public class outside.Test extends java.lang.Object{
public outside.Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
3: invokestatic #3; //Method java/lang/String.valueOf:(J)Ljava/lang/String;
6: astore_1
7: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
10: aload_1
11: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: goto 0
}观察结果表明,这两个例子之间没有差异。这是JVM规范的结果……
但出于最佳编码实践的考虑,建议在尽可能小的范围内声明变量(在本例中,变量在循环内,因为这是使用变量的唯一位置)。
发布于 2012-01-22 04:26:47
在最小的作用域中声明对象可以提高的可读性。
对于今天的编译器来说,性能并不重要。(在这个场景中)
从维护的角度来看, option 选项更好。
在同一位置声明和初始化变量,并尽可能缩小作用域。
正如Donald Ervin Knuth所说:
“我们应该忘记小的效率,比如说97%的时间:过早的优化是一切邪恶的根源”
即,程序员让性能考虑因素影响一段代码的设计的情况。这可能会导致设计不像原本那样干净的,或者代码不正确,因为优化使代码变得复杂复杂(),并且程序员被优化分散了注意力。
https://stackoverflow.com/questions/8803674
复制相似问题