在 Java 中迭代数组的最快方法:循环变量与增强的 for 语句

2022-01-24 00:00:00 performance iteration java

在 Java 中,以老式方式遍历数组是否更快,

In Java, is it faster to iterate through an array the old-fashioned way,

for (int i = 0; i < a.length; i++)
    f(a[i]);

或者使用更简洁的形式,

Or using the more concise form,

for (Foo foo : a)
    f(foo);

对于一个ArrayList,答案是否一样?

For an ArrayList, is the answer the same?

当然,对于大量应用程序代码,答案是它没有明显的区别,因此应使用更简洁的形式以提高可读性.然而,我正在查看的上下文是重型技术计算,必须执行数十亿次的操作,因此即使是微小的速度差异最终也可能很重要.

Of course for the vast bulk of application code, the answer is it makes no discernible difference so the more concise form should be used for readability. However the context I'm looking at is heavy duty technical computation, with operations that must be performed billions of times, so even a tiny speed difference could end up being significant.

推荐答案

如果你正在循环遍历一个数组,这无关紧要 - 增强的 for 循环无论如何都会使用数组访问.

If you're looping through an array, it shouldn't matter - the enhanced for loop uses array accesses anyway.

例如,考虑以下代码:

public static void main(String[] args)
{
    for (String x : args)
    {
        System.out.println(x);
    }
}

当使用 javap -c Test 反编译时,我们得到(对于 main 方法):

When decompiled with javap -c Test we get (for the main method):

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

现在将其更改为使用显式数组访问:

Now change it to use an explicit array access:

public static void main(String[] args)
{
    for (int i = 0; i < args.length; i++)
    {
        System.out.println(args[i]);
    }
}

这反编译为:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   aload_0
   4:   arraylength
   5:   if_icmpge   23
   8:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  aload_0
   12:  iload_1
   13:  aaload
   14:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   17:  iinc    1, 1
   20:  goto    2
   23:  return

在增强的 for 循环中有更多设置代码,但它们基本上在做同样的事情.不涉及迭代器.此外,我希望他们能够 JITted 到更相似的代码.

There's a bit more setup code in the enhanced for loop, but they're basically doing the same thing. No iterators are involved. Furthermore, I'd expect them to get JITted to even more similar code.

建议:如果您真的认为它可能会产生显着差异(只有在循环体绝对微不足道的情况下,它才会永远这样做),那么您应该用您的实际应用程序对其进行基准测试.这是唯一重要的情况.

Suggestion: if you really think it might make a significant difference (which it would only ever do if the body of the loop is absolutely miniscule) then you should benchmark it with your real application. That's the only situation which matters.

相关文章