如果有的话,下面两个循环之间的性能差异是什么?
for (Object o: objectArrayList) {
o.DoSomething();
}
and
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
如果有的话,下面两个循环之间的性能差异是什么?
for (Object o: objectArrayList) {
o.DoSomething();
}
and
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
当前回答
for-each循环通常是首选的。如果您使用的List实现不支持随机访问,那么“get”方法可能会慢一些。例如,如果使用LinkedList,则会产生遍历代价,而For -each方法使用迭代器跟踪其在列表中的位置。关于for-each循环的细微差别的更多信息。
我想文章现在在这里:新的位置
这里显示的链接已经失效。
其他回答
即使使用像ArrayList或Vector这样的东西,其中“get”是一个简单的数组查找,第二个循环仍然有第一个循环没有的额外开销。我预计它会比第一次慢一点。
以下代码:
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循环中)时,你可以避免性能损失,同时保持可读性。
1. for(Object o: objectArrayList){
o.DoSomthing();
}
and
2. for(int i=0; i<objectArrayList.size(); i++){
objectArrayList.get(i).DoSomthing();
}
两者都做同样的事情,但为了方便和安全的编程使用,在第二种使用方式中有容易出错的可能性。
Foreach使你的代码的意图更清晰,这通常比非常小的速度改进更受欢迎——如果有的话。
每当我看到一个索引循环,我必须解析它一段时间,以确保它做什么,我认为它做,例如,它是否从零开始,它是否包括或排除终点等?
我的大部分时间似乎都花在了阅读代码(我写的或别人写的)上,而清晰度几乎总是比性能更重要。现在很容易忽略Hotspot的性能,因为Hotspot做得非常出色。
以下是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.