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

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循环的细微差别的更多信息。

我想文章现在在这里:新的位置

这里显示的链接已经失效。

其他回答

所有这些循环都是一样的,我只是想在发表我的观点之前展示一下。

首先,循环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循环之前和之后,都要对软件进行良好的基准测试。

for-each循环通常是首选的。如果您使用的List实现不支持随机访问,那么“get”方法可能会慢一些。例如,如果使用LinkedList,则会产生遍历代价,而For -each方法使用迭代器跟踪其在列表中的位置。关于for-each循环的细微差别的更多信息。

我想文章现在在这里:新的位置

这里显示的链接已经失效。

在我看来,其他答案都是基于错误的基准测试,没有考虑Hotspot的编译和优化过程。

简短的回答

尽可能使用增强循环,因为大多数时候它是最快的。 如果不能,如果可能的话,将整个数组拉到一个局部变量中:

int localArray = this.array;
for (int i = 0; i < localArray.length; i++) { 
    methodCall(localArray[i]); 
}

长回答

现在,通常没有区别,因为Hotspot非常擅长优化和消除java需要做的检查。

但有时一些优化就是无法完成,通常是因为在循环中有一个虚拟调用,不能内联。 在这种情况下,有些循环确实比其他循环快。

Java需要做的一些事情:

重新加载。数组——因为它可以被改变(通过调用或另一个线程) 检查i是否在数组的边界内,如果不是抛出IndexOutOfBoundsException 检查被访问对象引用是否为空,如果是则抛出NullPointerException异常

考虑一下这个c风格的循环:

for (int i = 0; i < this.array.length; i++) { //now java knows i < this.array.length
    methodCall(this.array[i]);// no need to check
}

通过计算循环条件i < this.array。长度,Java知道I必须在边界内(I只在调用后更改),所以不需要在下一行中再次检查它。 但在这种情况下,java需要重新加载this.array.length。

你可能会想通过将this.array.length值拉到局部变量内部来“优化”循环:

int len = this.array.length;//len is now a local variable
for (int i = 0; i < len; i++) { //no reload needed
    methodCall(this.array[i]); //now java will do the check
}

现在java不需要每次都重新加载,因为局部变量可以被methodCall和/或另一个线程改变。局部变量只能在方法本身内部更改,java现在可以证明变量len不能更改。

但是现在循环条件i < this.array.length变为i < len,之前的优化失败,java需要检查i in是否在this.array的边界内。

一个更好的优化方法是将整个数组拉入一个局部变量:

ArrayType[] localArray = this.array;
for (int i = 0; i < localArray.length; i++) { 
    methodCall(localArray[i]); 
}

现在java不需要重新加载数组,“i in bounds”检查也被取消了。

那强化循环呢? 好吧,通常编译器会把增强的循环重写成类似上次显示的循环的东西,如果不是更好的话。

Foreach使你的代码的意图更清晰,这通常比非常小的速度改进更受欢迎——如果有的话。

每当我看到一个索引循环,我必须解析它一段时间,以确保它做什么,我认为它做,例如,它是否从零开始,它是否包括或排除终点等?

我的大部分时间似乎都花在了阅读代码(我写的或别人写的)上,而清晰度几乎总是比性能更重要。现在很容易忽略Hotspot的性能,因为Hotspot做得非常出色。

唯一确定的方法是对其进行基准测试,甚至这也不像听起来那么简单。JIT编译器可以对代码做一些意想不到的事情。