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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1006395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:11:21  来源:igfitidea点击:

Fastest way to iterate an Array in Java: loop variable vs enhanced for statement

javaperformanceiteration

提问by rwallace

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

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

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

Or using the more concise form,

或者使用更简洁的形式,

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

For an ArrayList, is the answer the same?

对于 ArrayList,答案是否相同?

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.

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

采纳答案by Jon Skeet

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

如果您正在遍历一个数组,那应该没有关系 - 增强的 for 循环无论如何都使用数组访问。

For example, consider this code:

例如,考虑以下代码:

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

When decompiled with javap -c Testwe get (for the mainmethod):

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

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]);
    }
}

This decompiles to:

这反编译为:

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

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.

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

Suggestion: if you really think it might make a significant difference (which it would only everdo 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.

建议:如果你真的认为它可能使一个显著差异(这只会永远做,如果循环体是绝对微乎其微),那么你应该基准它与您的实际应用。这是唯一重要的情况。

回答by cletus

This falls squarely in the arena of micro-optimization. It really doesn't matter. Stylistically I always prefer the second because it's more concise, unless you need the loop counter for something else. And that's far more important than this kind of micro-optimization: readability.

这完全属于微优化领域。真的没关系。从风格上讲,我总是更喜欢第二种,因为它更简洁,除非您需要循环计数器来做其他事情。这比这种微优化重要得多:可读性。

That being said, For an ArrayList there won't be much difference but a LinkedList will be much more efficient with the second.

话虽如此,对于 ArrayList 不会有太大区别,但 LinkedList 与第二个相比会更有效率。

回答by Mnementh

Measure it. The answer on all performance-questions can depend on VM-version, processor, memory-speed, caches etc. So you have to measure it for your particular platform.

测量它。所有性能问题的答案都取决于 VM 版本、处理器、内存速度、缓存等。因此您必须针对您的特定平台对其进行测量。

Personally I would prefer the second variant, because the intention is more clear. If performance becomes a problem I can optimize it later anyways - if that code really is important for the performance of the whole application.

我个人更喜欢第二种变体,因为意图更明确。如果性能成为一个问题,我可以稍后对其进行优化 - 如果该代码对整个应用程序的性能真的很重要。

回答by gubby

On an array, or RandomAccess collection you can get a tiny increase in speed by doing:

在数组或 RandomAccess 集合上,您可以通过执行以下操作来略微提高速度:

List<Object> list = new ArrayList<Object>();

for (int i=0, d=list.size(); i<d; i++) {
    something(list.get(i));
}

But I wouldn't worry in general. Optimisations like this wont make more than 0.1% difference to your code. Try invoking java with -profto see where your code is actually spending its time.

但我一般不会担心。像这样的优化不会对您的代码产生超过 0.1% 的差异。尝试使用-prof调用 java以查看您的代码实际花费的时间。

回答by akarnokd

Even faster is to use the ParallelArray of the fork-join framework (if you have large enough dataset).

更快的是使用 fork-join 框架的 ParallelArray(如果你有足够大的数据集)。

回答by David García González

For a LinkedList:

对于链表:

for(ClassOfElement element : listOfElements) {
  System.out.println(element.getValue());
}

It was answered before:

之前有人回答过:

Is there a performance difference between a for loop and a for-each loop?

for 循环和 for-each 循环之间是否存在性能差异?