如果有的话,下面两个循环之间的性能差异是什么?

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

and

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

当前回答

以下代码:

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的Ubuntu 12.10 alpha。

一般来说,HotSpot优化了大量的间接操作和简单的冗余操作,所以一般情况下,您不必担心它们,除非它们有很多顺序或嵌套严重。

另一方面,LinkedList上的索引get比LinkedList上的next On迭代器要慢得多,所以当你使用迭代器(显式或隐式地在for-each循环中)时,你可以避免性能损失,同时保持可读性。

其他回答

对性能的影响基本上是微不足道的,但也不是零。如果你看看JavaDoc的RandomAccess接口:

根据经验,一个列表 实现应该实现这个 的典型实例 这个类,这个循环: For (int i=0, n=list.size();I < n;我+ +) list.get(我); 运行速度比这个循环快: for(迭代器i=list.iterator();i.hasNext (); i.next ();

for-each循环使用version with iterator,以ArrayList为例,for-each循环不是最快的。

奇怪的是,没有人提到显而易见的——foreach分配内存(以迭代器的形式),而普通的for循环不分配任何内存。对于Android游戏来说,这是个问题,因为这意味着垃圾收集器将周期性地运行。在游戏中,你不希望垃圾回收器运行……永远。所以不要在你的绘制(或渲染)方法中使用foreach循环。

以下代码:

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的Ubuntu 12.10 alpha。

一般来说,HotSpot优化了大量的间接操作和简单的冗余操作,所以一般情况下,您不必担心它们,除非它们有很多顺序或嵌套严重。

另一方面,LinkedList上的索引get比LinkedList上的next On迭代器要慢得多,所以当你使用迭代器(显式或隐式地在for-each循环中)时,你可以避免性能损失,同时保持可读性。

即使使用像ArrayList或Vector这样的东西,其中“get”是一个简单的数组查找,第二个循环仍然有第一个循环没有的额外开销。我预计它会比第一次慢一点。

以下是Android开发团队对两者差异的简要分析:

https://www.youtube.com/watch?v=MZOf3pOAM6A

The result is that there is a difference, and in very restrained environments with very large lists it could be a noticeable difference. In their testing, the for each loop took twice as long. However, their testing was over an arraylist of 400,000 integers. The actual difference per element in the array was 6 microseconds. I haven't tested and they didn't say, but I would expect the difference to be slightly larger using objects rather than primitives, but even still unless you are building library code where you have no idea the scale of what you will be asked to iterate over, I think the difference is not worth stressing about.