如果有的话,下面两个循环之间的性能差异是什么?
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();
}
当前回答
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迭代。
其他回答
1. for(Object o: objectArrayList){
o.DoSomthing();
}
and
2. for(int i=0; i<objectArrayList.size(); i++){
objectArrayList.get(i).DoSomthing();
}
两者都做同样的事情,但为了方便和安全的编程使用,在第二种使用方式中有容易出错的可能性。
唯一确定的方法是对其进行基准测试,甚至这也不像听起来那么简单。JIT编译器可以对代码做一些意想不到的事情。
奇怪的是,没有人提到显而易见的——foreach分配内存(以迭代器的形式),而普通的for循环不分配任何内存。对于Android游戏来说,这是个问题,因为这意味着垃圾收集器将周期性地运行。在游戏中,你不希望垃圾回收器运行……永远。所以不要在你的绘制(或渲染)方法中使用foreach循环。
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迭代。
通过变量名称objectArrayList,我假设它是java.util.ArrayList的一个实例。在这种情况下,性能差异是不明显的。
另一方面,如果它是java.util的实例。LinkedList,第二种方法会慢得多,因为list# get(int)是一个O(n)操作。
因此,第一种方法总是首选的,除非循环中的逻辑需要索引。