如果有的话,下面两个循环之间的性能差异是什么?
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();
}
当前回答
对性能的影响基本上是微不足道的,但也不是零。如果你看看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循环不是最快的。
其他回答
摘自Joshua Bloch的《Effective Java》第46条:
The for-each loop, introduced in release 1.5, gets rid of the clutter and the opportunity for error by hiding the iterator or index variable completely. The resulting idiom applies equally to collections and arrays: // The preferred idiom for iterating over collections and arrays for (Element e : elements) { doSomething(e); } When you see the colon (:), read it as “in.” Thus, the loop above reads as “for each element e in elements.” Note that there is no performance penalty for using the for-each loop, even for arrays. In fact, it may offer a slight performance advantage over an ordinary for loop in some circumstances, as it computes the limit of the array index only once. While you can do this by hand (Item 45), programmers don’t always do so.
Foreach使你的代码的意图更清晰,这通常比非常小的速度改进更受欢迎——如果有的话。
每当我看到一个索引循环,我必须解析它一段时间,以确保它做什么,我认为它做,例如,它是否从零开始,它是否包括或排除终点等?
我的大部分时间似乎都花在了阅读代码(我写的或别人写的)上,而清晰度几乎总是比性能更重要。现在很容易忽略Hotspot的性能,因为Hotspot做得非常出色。
不幸的是,两者之间似乎存在差异。
如果查看这两种循环生成的字节代码,就会发现它们是不同的。
下面是来自Log4j源代码的一个示例。
在/log4j-api/src/main/java/org/apache/ loggging/ log4j/ markermanager .java中,我们有一个名为Log4jMarker的静态内部类,它定义了:
/*
* Called from add while synchronized.
*/
private static boolean contains(final Marker parent, final Marker... localParents) {
//noinspection ForLoopReplaceableByForEach
for (final Marker marker : localParents) {
if (marker == parent) {
return true;
}
}
return false;
}
使用标准循环:
private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
Code:
0: iconst_0
1: istore_2
2: aload_1
3: arraylength
4: istore_3
5: iload_2
6: iload_3
7: if_icmpge 29
10: aload_1
11: iload_2
12: aaload
13: astore 4
15: aload 4
17: aload_0
18: if_acmpne 23
21: iconst_1
22: ireturn
23: iinc 2, 1
26: goto 5
29: iconst_0
30: ireturn
for - each:
private static boolean contains(org.apache.logging.log4j.Marker, org.apache.logging.log4j.Marker...);
Code:
0: aload_1
1: astore_2
2: aload_2
3: arraylength
4: istore_3
5: iconst_0
6: istore 4
8: iload 4
10: iload_3
11: if_icmpge 34
14: aload_2
15: iload 4
17: aaload
18: astore 5
20: aload 5
22: aload_0
23: if_acmpne 28
26: iconst_1
27: ireturn
28: iinc 4, 1
31: goto 8
34: iconst_0
35: ireturn
那个神谕是怎么回事?
我在Windows 7上用Java 7和Java 8尝试过。
对性能的影响基本上是微不足道的,但也不是零。如果你看看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循环不是最快的。
使用迭代器总是比使用索引更好。这是因为iterator最有可能针对List实现进行了优化,而索引(调用get)可能没有。例如,LinkedList是一个List,但是通过它的元素建立索引将比使用迭代器迭代慢。