以下哪个Java编码片段更好?

Sim*_*mon 4 java scope

这不是主观的,我正在寻找基于资源利用率,编译器性能,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运算符.这些半风格的半优化中的任何一种都没有任何区别吗?

Mic*_*ers 7

第二个是我更喜欢的.除了范围之外没有其他功能差异.

在每次迭代中设置相同的变量没有区别,因为它Integer是一个不可变的类.现在,如果你每次修改一个对象而不是创建一个新对象,那么就会有所不同.

而作为一个侧面说明,在此代码,你应该使用intInteger.parseInt(),而不是IntegerInteger.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即使从实际代码中省略了变量,变量仍然占用了一个寄存器(请注意,所有iloadistore指令都指向一个寄存器更高).

JIT编译器应该对这种差异进行简短的处理,但是你仍然可以看到限制范围是一种很好的做法.

(关于我之前的附注,你可以看到要添加两个Integer对象,Java必须同时取消intValue,添加它们,然后创建一个新的Integer valueOf.除非绝对必要,否则不要这样做,因为它没有意义,慢点.)