for循环条件:数组大小 - .length还是常量?

时间:2014-03-26 16:05:23

标签: java arrays for-loop

说,我已经使用常量来为数组分配空间。

后来,当我使用for循环访问数组中的每个位置时,是否应该使用数组的.length值或声明期间使用的常量值来寻址测试部分?

换句话说,

for (int i = 0; i < array.length; i++)

for (int i = 0; i < constantArraySize; i++)

哪一个更好?

5 个答案:

答案 0 :(得分:4)

考虑到性能,没有一个应该优于另一个。两者都应该在缓存中。

考虑到可读性,您应该使用array.length来明确您想要遍历数组。所以我会选择第一个替代方案。

答案 1 :(得分:0)

我认为你最好的选择是foreach:

for (Item item : array) {
    // Do stuff
}

编译器会为您优化它,并且更容易阅读。万岁!


优化,你说?确实。通常它不会有所作为,但如果它更容易阅读和更快,为什么不这样做呢?

考虑这个课程:

final int SIZE = 3;
final String[] a = new String[SIZE];

void doStuff(String s){}

void useLength(){
    for (int i = 0; i < a.length; i++) {
        doStuff(a[i]);
    }
}

void useConstant(){
    for (int i = 0; i < SIZE; i++) {
        doStuff(a[i]);
    }
}

void useForEach(){
    for (String s : a) {
        doStuff(s);
    }
}

反编译,我们得到这段代码:

  void useLength();
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: aload_0       
       4: getfield      #4                  // Field a:[Ljava/lang/String;
       7: arraylength   
       8: if_icmpge     27
      11: aload_0       
      12: aload_0       
      13: getfield      #4                  // Field a:[Ljava/lang/String;
      16: iload_1       
      17: aaload        
      18: invokevirtual #5                  // Method doStuff:(Ljava/lang/String;)V
      21: iinc          1, 1
      24: goto          2
      27: return   

因此,如果数组是字段,则使用length将每次迭代加载字段两次。如果该字段引起刷新(例如,如果它是易失性的,或者JIT处于不良情绪中等),则这可以产生差异。如果通过并发线程访问封闭对象(该数组可以在操作7和17之间更改),它也不是线程安全的。

  void useConstant();
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: iconst_3      
       4: if_icmpge     23
       7: aload_0       
       8: aload_0       
       9: getfield      #4                  // Field a:[Ljava/lang/String;
      12: iload_1       
      13: aaload        
      14: invokevirtual #5                  // Method doStuff:(Ljava/lang/String;)V
      17: iinc          1, 1
      20: goto          2
      23: return     

每次迭代只进行一次字段访问,但如果星星是正确的,它仍然会花费我们。如果字段更改值,它也会有相当未指定的行为。

Foreach做的事情略有不同:

  void useForEach();
    Code:
       0: aload_0       
       1: getfield      #4                  // Field a:[Ljava/lang/String;
       4: astore_1      
       5: aload_1       
       6: arraylength   
       7: istore_2      
       8: iconst_0      
       9: istore_3      
      10: iload_3       
      11: iload_2       
      12: if_icmpge     32
      15: aload_1       
      16: iload_3       
      17: aaload        
      18: astore        4
      20: aload_0       
      21: aload         4
      23: invokevirtual #5                  // Method doStuff:(Ljava/lang/String;)V
      26: iinc          3, 1
      29: goto          10
      32: return 

只有一个字段访问,一个数组长度检查!它大致相当于:

void useForEach(){
    String[] localArr = arr;
    for (int i = 0, length = arr.length; i < length; i++) {
        doStuff(localArr[i]);
    }
}

答案 2 :(得分:0)

由于数组是大小固定的,因此使用哪一个并不重要。除非你修改了数组的引用。让我们看看这个例子:

public class Test
{
    final int SIZE = 3;
    int[] arr;

    public Test()
    {
        arr = new int[SIZE];
        print();

        arr = new int[SIZE - 1]; // modify
        print();
    }

    public void print()
    {
        for (int i = 0; i < SIZE; i++) {
            System.out.println(arr[i]);
        }
    }

    public static void main(String[] args)
    {
        Test t = new Test();
    }
}

<强>输出:

0
0
0
0
0
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
    at testpackage.Test.print(Test.java:19)
    at testpackage.Test.<init>(Test.java:13)
    at testpackage.Test.main(Test.java:25)

您将收到异常,因为您已将对较小尺寸的数组的引用更改为。如果您使用arr.length,则不会出现此问题。除非您确定不会修改arr的引用,否则可以使用常量。

答案 3 :(得分:0)

由于数组是不可变的(我的意思是它的长度不能改变),从功能的角度来看这无关紧要。

从性能的角度来看,对本地变量和array.length的访问也是相同的。

例如,如果你有几个相同长度的数组,或者你有任何其他原因使用array.length在特定上下文中的可读性低于使用特殊变量,那么这可能很重要。

答案 4 :(得分:0)

以上两种方法无关紧要。

但如果有任何计算,

<强> e.g

for(int i=0;i< (j*10+10);i++)
{
}

您应该将该计算保存到变量中,并在条件

中使用它

int temp=j*10+10;
for(int i=0;i<temp;i++)
{
}

进行代码优化。