当前位置: 首页 > 面试题库 >

增强的循环性能比传统的索引查找差吗?

林元明
2023-03-14
问题内容

我刚刚遇到了这个看似无害的评论,对ArrayList和原始String数组进行了基准测试。是几年前的事,但OP写道

我确实注意到,使用String:stringsList比使用旧式的for循环访问列表要慢大约50%。去搞清楚…

在原始帖子中没有人对此发表评论,并且该测试似乎有点可疑(太短了以至于不够准确),但是当我阅读它时,我几乎掉下了椅子。我从未针对“传统”循环对增强循环进行基准测试,但是我目前正在开发一个项目,该项目使用增强循环对ArrayList实例进行了数亿次迭代,因此这是我关心的问题。

我将进行一些基准测试并将结果发布在这里,但这显然是我的最大担忧。我可以在网上找到关于相对性能的宝贵信息,除了一些副手提到的ArrayLists增强循环在Android下运行得慢得多。

有人经历过吗?这样的性能差距是否仍然存在?我将在这里发表我的发现,但是读起来很惊讶。我怀疑如果确实存在这种性能差距,那么它已经在更现代的VM中得到了解决,但是我想现在我必须进行一些测试并确认。

更新:
我对代码进行了一些更改,但是已经怀疑这里的其他内容已经指出:确保增强的for循环速度较慢,但​​是在非常琐碎的紧密循环之外,成本应该只是该代码成本的很小一部分。循环逻辑。就我而言,即使我使用增强的循环遍历非常大的字符串列表,循环中的逻辑也很复杂,以至于在切换到基于索引的循环后我什至无法测量出差异。

TL; DR: 增强循环的确比阵列列表上传统的基于索引的循环慢。但对于大多数应用而言,差异应该可以忽略不计。


问题答案:

您遇到的问题是,使用迭代器比使用直接查找要慢。在我的机器上,每次迭代的差异约为0.13 ns。相反,使用数组可以为每次迭代节省0.15
ns。在99%的情况下,这应该是微不足道的。

public static void main(String... args) {
    int testLength = 100 * 1000 * 1000;
    String[] stringArray = new String[testLength];
    Arrays.fill(stringArray, "a");
    List<String> stringList = new ArrayList<String>(Arrays.asList(stringArray));
    {
        long start = System.nanoTime();
        long total = 0;
        for (String str : stringArray) {
            total += str.length();
        }
        System.out.printf("The for each Array loop time was %.2f ns total=%d%n", (double) (System.nanoTime() - start) / testLength, total);
    }
    {
        long start = System.nanoTime();
        long total = 0;
        for (int i = 0, stringListSize = stringList.size(); i < stringListSize; i++) {
            String str = stringList.get(i);
            total += str.length();
        }
        System.out.printf("The for/get List loop time was %.2f ns total=%d%n", (double) (System.nanoTime() - start) / testLength, total);
    }
    {
        long start = System.nanoTime();
        long total = 0;
        for (String str : stringList) {
            total += str.length();
        }
        System.out.printf("The for each List loop time was %.2f ns total=%d%n", (double) (System.nanoTime() - start) / testLength, total);
    }
}

当运行十亿个条目时,将打印条目(使用Java 6 update26。)

The for each Array loop time was 0.76 ns total=1000000000
The for/get List loop time was 0.91 ns total=1000000000
The for each List loop time was 1.04 ns total=1000000000

当运行十亿个条目时,将打印条目(使用OpenJDK7。)

The for each Array loop time was 0.76 ns total=1000000000
The for/get List loop time was 0.91 ns total=1000000000
The for each List loop time was 1.04 ns total=1000000000

即完全一样。;)



 类似资料:
  • 所以我的理解是,增强for循环应该更慢,因为它们必须使用迭代器。。然而,我的代码提供的结果参差不齐。。(是的,我知道循环逻辑占用了循环中的大部分时间) 对于较少的迭代次数(100-1000),无论有无JIT,增强的For循环似乎都要快得多。相反,对于大量迭代(100000000),传统循环速度要快得多。这是怎么回事?

  • 我正在逐个迭代字符串对象列表中的元素: 在这里,每次我调用list上的get()时,列表都会从其一端一直迭代到第i个元素——因此上面循环的复杂性是O(n^2)。 是a.)对于增强型for循环,与上面相同,还是b.)对于循环,将指针保持在最后一个指针所在的位置,因此下面循环的复杂性是O(n)? 如果上面的情况(b)——我想是这样的——在列表上使用迭代器有什么好处吗。这是简单的迭代--没有回头路 蒂亚

  • 问题内容: 是否可以在增强的for循环中找到当前索引?如果可以,怎么办? 我知道我们可以用一个额外的变量来检查它。但是还有其他方法。 问题答案: 是否可以在增强的for循环中找到当前索引? 不。如果需要索引,建议您使用普通的for循环。 但是,在这种情况下,您似乎实际上并不需要索引。除非您要处理某种非常奇怪的列表类型,否则可以使用和使用方法,如下所示:

  • 我想知道,在这种情况下,我们可以使用增强的for而不是常规的for循环 在这种情况下,我可以使用增强的for吗?

  • 问题内容: 在Java中的for循环中防止空值的最佳方法是什么? 这看起来很丑: 要么 可能没有其他办法。他们是否应该将它放在构造本身中,如果它为null,则不要运行循环? 问题答案: 您最好验证从哪里获得该列表。 空列表就是您所需要的,因为空列表不会失败。 如果您从其他地方获得此列表,并且不知道是否可以,则可以创建一个实用程序方法并像这样使用它: 当然是:

  • 问题内容: 我正在从Java切换到C ,并且想知道C 是否包含我在Java中使用的增强的for循环,例如: 在C ++中是否可能有相同的“快捷方式”? 问题答案: 在C ++ 11中,如果编译器支持,则可以。这称为基于范围的。 它适用于C样式数组以及具有函数并返回迭代器的任何类型。例: