这不是主观的,我正在寻找基于资源利用率,编译器性能,GC性能等而不是优雅的原因.哦,括号的位置不算,所以没有风格的评论.
采取以下循环;
Integer total = new Integer(0);
Integer i;
for (String str : string_list)
{
i = Integer.parse(str);
total += i;
}
Run Code Online (Sandbox Code Playgroud)
与...
Integer total = 0;
for (String str : string_list)
{
Integer i = Integer.parse(str);
total += i;
}
Run Code Online (Sandbox Code Playgroud)
在第一个中,我是函数作用域,而在第二个中,它是在循环中作用域.我一直认为(相信)第一个会更高效,因为它只引用已经在堆栈上分配的现有变量,而第二个将在循环的每次迭代中推送和弹出.
还有很多其他情况我倾向于将变量范围扩大到可能需要的范围,所以我想我会在这里要求澄清我的知识差距.还要注意初始化时变量的赋值是否涉及new运算符.这些半风格的半优化中的任何一种都没有任何区别吗?
第二个是我更喜欢的.除了范围之外没有其他功能差异.
在每次迭代中设置相同的变量没有区别,因为它Integer是一个不可变的类.现在,如果你每次修改一个对象而不是创建一个新对象,那么就会有所不同.
而作为一个侧面说明,在此代码,你应该使用int和Integer.parseInt(),而不是Integer和Integer.parse().你引入了相当多的不必要的拳击和拆箱.
编辑:自从我在字节码中乱码以来已经有一段时间了,所以我想我会再次弄脏手.
这是我编译的测试类:
class ScopeTest {
public void outside(String[] args) {
Integer total = 0;
Integer i;
for (String str : args)
{
i = Integer.valueOf(str);
total += i;
}
}
public void inside(String[] args) {
Integer total = 0;
for (String str : args)
{
Integer i = Integer.valueOf(str);
total += i;
}
}
}
Run Code Online (Sandbox Code Playgroud)
字节码输出(javap -c ScopeTest在编译后检索):
Compiled from "ScopeTest.java"
class ScopeTest extends java.lang.Object{
ScopeTest();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public void outside(java.lang.String[]);
Code:
0: iconst_0
1: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_2
5: aload_1
6: astore 4
8: aload 4
10: arraylength
11: istore 5
13: iconst_0
14: istore 6
16: iload 6
18: iload 5
20: if_icmpge 55
23: aload 4
25: iload 6
27: aaload
28: astore 7
30: aload 7
32: invokestatic #3; //Method java/lang/Integer.valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
35: astore_3
36: aload_2
37: invokevirtual #4; //Method java/lang/Integer.intValue:()I
40: aload_3
41: invokevirtual #4; //Method java/lang/Integer.intValue:()I
44: iadd
45: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
48: astore_2
49: iinc 6, 1
52: goto 16
55: return
public void inside(java.lang.String[]);
Code:
0: iconst_0
1: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_2
5: aload_1
6: astore_3
7: aload_3
8: arraylength
9: istore 4
11: iconst_0
12: istore 5
14: iload 5
16: iload 4
18: if_icmpge 54
21: aload_3
22: iload 5
24: aaload
25: astore 6
27: aload 6
29: invokestatic #3; //Method java/lang/Integer.valueOf:(Ljava/lang/String;)Ljava/lang/Integer;
32: astore 7
34: aload_2
35: invokevirtual #4; //Method java/lang/Integer.intValue:()I
38: aload 7
40: invokevirtual #4; //Method java/lang/Integer.intValue:()I
43: iadd
44: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
47: astore_2
48: iinc 5, 1
51: goto 14
54: return
}
Run Code Online (Sandbox Code Playgroud)
与我的期望相反,两者之间存在一个区别:在outside()变量中,i即使从实际代码中省略了变量,变量仍然占用了一个寄存器(请注意,所有iload和istore指令都指向一个寄存器更高).
JIT编译器应该对这种差异进行简短的处理,但是你仍然可以看到限制范围是一种很好的做法.
(关于我之前的附注,你可以看到要添加两个Integer对象,Java必须同时取消intValue,添加它们,然后创建一个新的Integer valueOf.除非绝对必要,否则不要这样做,因为它没有意义,慢点.)