如果有的话,下面两个循环之间的性能差异是什么?
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();
}
当前回答
通过变量名称objectArrayList,我假设它是java.util.ArrayList的一个实例。在这种情况下,性能差异是不明显的。
另一方面,如果它是java.util的实例。LinkedList,第二种方法会慢得多,因为list# get(int)是一个O(n)操作。
因此,第一种方法总是首选的,除非循环中的逻辑需要索引。
其他回答
使用迭代器总是比使用索引更好。这是因为iterator最有可能针对List实现进行了优化,而索引(调用get)可能没有。例如,LinkedList是一个List,但是通过它的元素建立索引将比使用迭代器迭代慢。
对性能的影响基本上是微不足道的,但也不是零。如果你看看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循环不是最快的。
所有这些循环都是一样的,我只是想在发表我的观点之前展示一下。
首先,循环List的经典方法:
for (int i=0; i < strings.size(); i++) { /* do something using strings.get(i) */ }
其次,这是首选的方法,因为它更不容易出错(你有多少次做过“哎呀,在这些循环中循环中混合变量i和j”的事情?)
for (String s : strings) { /* do something using s */ }
第三,微优化for循环:
int size = strings.size();
for (int i = -1; ++i < size;) { /* do something using strings.get(i) */ }
现在真正的两美分:至少当我测试这些时,第三个是最快的,当计算每种类型的循环所花费的毫秒数时,其中一个简单的操作重复了数百万次——这是在Windows上使用Java 5和jre1.6u10,如果有人感兴趣的话。
While it at least seems to be so that the third one is the fastest, you really should ask yourself if you want to take the risk of implementing this peephole optimization everywhere in your looping code since from what I've seen, actual looping isn't usually the most time consuming part of any real program (or maybe I'm just working on the wrong field, who knows). And also like I mentioned in the pretext for the Java for-each loop (some refer to it as Iterator loop and others as for-in loop) you are less likely to hit that one particular stupid bug when using it. And before debating how this even can even be faster than the other ones, remember that javac doesn't optimize bytecode at all (well, nearly at all anyway), it just compiles it.
如果你喜欢微观优化,或者你的软件使用了很多递归循环,那么你可能会对第三种循环感兴趣。只需要记住,在更改for循环之前和之后,都要对软件进行良好的基准测试。
Accepted answer回答了这个问题,除了ArrayList…
因为大多数开发人员都依赖于ArrayList(至少我是这么认为的)
所以我有义务在这里加上正确答案。
直接从开发人员文档:-
增强的for循环(有时也称为“for-each”循环)可用于实现Iterable接口的集合和数组。对于集合,会分配一个迭代器来对hasNext()和next()进行接口调用。使用ArrayList,手工编写的计数循环大约快3倍(有或没有JIT),但对于其他集合,增强的for循环语法将完全等同于显式迭代器的使用。
有几种迭代数组的方法:
static class Foo {
int mSplat;
}
Foo[] mArray = ...
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
zero()是最慢的,因为JIT还不能优化掉每次循环迭代获取数组长度的成本。
一个()比较快。它将所有内容提取到局部变量中,避免了查找。只有数组长度能带来性能上的好处。
two()对于没有JIT的设备来说是最快的,对于有JIT的设备来说与one()是没有区别的。它使用Java编程语言1.5版中引入的增强for循环语法。
因此,默认情况下您应该使用增强的for循环,但是可以考虑使用手写的计数循环来进行性能关键的ArrayList迭代。
奇怪的是,没有人提到显而易见的——foreach分配内存(以迭代器的形式),而普通的for循环不分配任何内存。对于Android游戏来说,这是个问题,因为这意味着垃圾收集器将周期性地运行。在游戏中,你不希望垃圾回收器运行……永远。所以不要在你的绘制(或渲染)方法中使用foreach循环。