首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >for循环和for-each循环之间是否存在性能差异?

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

Stack Overflow用户
提问于 2008-11-02 12:40:53
回答 10查看 127.6K关注 0票数 198

下面两个循环之间的性能差异是什么?

for (Object o: objectArrayList) {
    o.DoSomething();
}

for (int i=0; i<objectArrayList.size(); i++) {
    objectArrayList.get(i).DoSomething();
}
EN

回答 10

Stack Overflow用户

发布于 2008-11-02 13:07:58

通常应该首选for-each循环。如果您使用的列表实现不支持随机访问,则"get“方法可能会较慢。例如,如果使用LinkedList,则会产生遍历开销,而for-each方法使用迭代器来跟踪它在列表中的位置。有关nuances of the for-each loop的更多信息。

我想文章现在已经在这里了:new location

这里显示的链接是死的。

票数 12
EN

Stack Overflow用户

发布于 2014-09-27 04:57:58

不幸的是,这似乎是有区别的。

如果您查看为这两种循环生成的字节代码,您会发现它们是不同的。

下面是Log4j源代码中的一个示例。

在/log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java中,我们有一个名为Log4jMarker的静态内部类,它定义:

    /*
     * Called from add while synchronized.
     */
    private static boolean contains(final Marker parent, final Marker... localParents) {
        //noinspection ForLoopReplaceableByForEach
        for (final Marker marker : localParents) {
            if (marker == parent) {
                return true;
            }
        }
        return false;
    }

使用标准循环:

  private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
    Code:
       0: iconst_0
       1: istore_2
       2: aload_1
       3: arraylength
       4: istore_3
       5: iload_2
       6: iload_3
       7: if_icmpge     29
      10: aload_1
      11: iload_2
      12: aaload
      13: astore        4
      15: aload         4
      17: aload_0
      18: if_acmpne     23
      21: iconst_1
      22: ireturn
      23: iinc          2, 1
      26: goto          5
      29: iconst_0
      30: ireturn

使用for-each:

  private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
    Code:
       0: aload_1
       1: astore_2
       2: aload_2
       3: arraylength
       4: istore_3
       5: iconst_0
       6: istore        4
       8: iload         4
      10: iload_3
      11: if_icmpge     34
      14: aload_2
      15: iload         4
      17: aaload
      18: astore        5
      20: aload         5
      22: aload_0
      23: if_acmpne     28
      26: iconst_1
      27: ireturn
      28: iinc          4, 1
      31: goto          8
      34: iconst_0
      35: ireturn

那个先知是怎么回事?

我已经在Windows7上的Java7和8上尝试过了。

票数 6
EN

Stack Overflow用户

发布于 2012-08-29 05:53:42

以下代码:

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;

interface Function<T> {
    long perform(T parameter, long x);
}

class MyArray<T> {

    T[] array;
    long x;

    public MyArray(int size, Class<T> type, long x) {
        array = (T[]) Array.newInstance(type, size);
        this.x = x;
    }

    public void forEach(Function<T> function) {
        for (T element : array) {
            x = function.perform(element, x);
        }
    }
}

class Compute {
    int factor;
    final long constant;

    public Compute(int factor, long constant) {
        this.factor = factor;
        this.constant = constant;
    }

    public long compute(long parameter, long x) {
        return x * factor + parameter + constant;
    }
}

public class Main {

    public static void main(String[] args) {
        List<Long> numbers = new ArrayList<Long>(50000000);
        for (int i = 0; i < 50000000; i++) {
            numbers.add(i * i + 5L);
        }

        long x = 234553523525L;

        long time = System.currentTimeMillis();
        for (int i = 0; i < numbers.size(); i++) {
            x += x * 7 + numbers.get(i) + 3;
        }
        System.out.println(System.currentTimeMillis() - time);
        System.out.println(x);
        x = 0;
        time = System.currentTimeMillis();
        for (long i : numbers) {
            x += x * 7 + i + 3;
        }
        System.out.println(System.currentTimeMillis() - time);
        System.out.println(x);
        x = 0;
        numbers = null;
        MyArray<Long> myArray = new MyArray<Long>(50000000, Long.class, 234553523525L);
        for (int i = 0; i < 50000000; i++) {
            myArray.array[i] = i * i + 3L;
        }
        time = System.currentTimeMillis();
        myArray.forEach(new Function<Long>() {

            public long perform(Long parameter, long x) {
                return x * 8 + parameter + 5L;
            }
        });
        System.out.println(System.currentTimeMillis() - time);
        System.out.println(myArray.x);
        myArray = null;
        myArray = new MyArray<Long>(50000000, Long.class, 234553523525L);
        for (int i = 0; i < 50000000; i++) {
            myArray.array[i] = i * i + 3L;
        }
        time = System.currentTimeMillis();
        myArray.forEach(new Function<Long>() {

            public long perform(Long parameter, long x) {
                return new Compute(8, 5).compute(parameter, x);
            }
        });
        System.out.println(System.currentTimeMillis() - time);
        System.out.println(myArray.x);
    }
}

在我的系统上给出以下输出:

224
-699150247503735895
221
-699150247503735895
220
-699150247503735895
219
-699150247503735895

我运行的是带有OracleJDK 1.7更新6的Ubuntu12.10alpha。

一般来说,HotSpot优化了很多间接和简单的冗余操作,所以通常你不应该担心它们,除非它们在序列中有很多或者它们是大量嵌套的。

另一方面,在LinkedList上索引的get比在LinkedList的迭代器上调用next慢得多,因此在使用迭代器(显式或隐式地在for-each循环中)时,可以避免这种性能影响,同时保持可读性。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/256859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档