efl*_*les 176 java performance for-loop
如果有的话,以下两个循环之间的性能差异是什么?
for (Object o: objectArrayList) {
o.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
和
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
Vij*_*Dev 202
来自Joshua Bloch的Effective Java中的第46项:
在1.5版中引入的for-each循环通过完全隐藏迭代器或索引变量来消除混乱和错误的机会.由此产生的习语同样适用于集合和数组:
Run Code Online (Sandbox Code Playgroud)// The preferred idiom for iterating over collections and arrays for (Element e : elements) { doSomething(e); }
当您看到冒号(:)时,将其读作"in".因此,上面的循环读作"对于元素中的每个元素e".请注意,使用for-each循环没有性能损失,即使对于数组也是如此.实际上,在某些情况下,它可能比普通的for循环提供轻微的性能优势,因为它只计算一次数组索引的限制.虽然您可以手动执行此操作(第45项),但程序员并不总是这样做.
P A*_*yah 29
所有这些循环完全相同,我只想在投入我的两分钱之前展示这些.
首先,循环遍历List的经典方法:
for(int i=0;i<strings.size();i++) { /* do something using strings.get(i) */ }
Run Code Online (Sandbox Code Playgroud)
第二,首选的方式,因为它不容易出错(你做了多少次"oops,在循环中的这些循环中混合变量i和j"的事情?).
for(String s : strings) { /* do something using s */ }
Run Code Online (Sandbox Code Playgroud)
三,微优化for循环:
int size = strings.size();
for(int i=0;++i<=size;) { /* do something using strings.get(i) */ }
Run Code Online (Sandbox Code Playgroud)
现在实际的两分钱:至少当我测试这些时,第三个是最快的,当计算毫秒数时每个类型的循环需要多长时间,其中一个简单的操作重复几百万次 - 这是使用Java 5在Windows上使用jre1.6u10,以防有人感兴趣.
虽然它至少看起来是第三个是最快的,但你真的应该问自己,你是否想要冒险在你的循环代码中实现这个窥孔优化的风险,因为从我所看到的,实际的循环不是'通常是任何真实程序中最耗时的部分(或者我只是在错误的领域工作,谁知道).而且就像我在Java for-each循环(有些人将其称为Iterator循环,其他人称为for-in循环)的借口中提到的那样,在使用它时,你不太可能遇到那个特定的愚蠢错误.在讨论如何甚至比其他的更快之前,请记住javac根本不优化字节码(好吧,几乎无论如何),它只是编译它.
如果您正在进行微优化和/或您的软件使用大量递归循环等,那么您可能会对第三个循环类型感兴趣.只需记住在更改for循环之前和之后都要对您的软件进行基准测试,这对于这个奇怪的,微优化的循环.
Zac*_*ena 13
通常应首选for-each循环.如果您使用的List实现不支持随机访问,则"get"方法可能会更慢.例如,如果使用LinkedList,则会产生遍历开销,而for-each方法使用迭代器来跟踪其在列表中的位置.有关for-each循环细微差别的更多信息.
我认为这篇文章现在在这里: 新的位置
这里显示的链接已经死了.
Sar*_*mun 11
那么,性能影响大多是微不足道的,但不是零.如果你看一下RandomAccess
界面的JavaDoc :
根据经验,对于类的典型实例,如果此循环,List实现应该实现此接口:
Run Code Online (Sandbox Code Playgroud)for (int i=0, n=list.size(); i < n; i++) list.get(i);
运行速度比这个循环快:
Run Code Online (Sandbox Code Playgroud)for (Iterator i=list.iterator(); i.hasNext();) i.next();
并且for-each循环使用带有迭代器的版本,因此ArrayList
例如,for-each循环不是最快的.
foreach 使您的代码的意图更清晰,并且通常比非常小的速度改进更受欢迎 - 如果有的话。
每当我看到一个索引循环时,我都必须对其进行更长时间的解析,以确保它执行我认为的操作,例如它是否从零开始,是否包含或排除终点等?
我的大部分时间似乎都花在阅读代码(我写的或其他人写的)上,清晰几乎总是比性能更重要。现在很容易忽略性能,因为 Hotspot 做得如此出色。
不幸的是,似乎存在差异.
如果你看两种循环的生成字节代码,它们是不同的.
以下是Log4j源代码的示例.
在/log4j-api/src/main/java/org/apache/logging/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;
}
Run Code Online (Sandbox Code Playgroud)
使用标准循环:
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
Run Code Online (Sandbox Code Playgroud)
随着每个:
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
Run Code Online (Sandbox Code Playgroud)
甲骨文怎么了?
我在Windows 7上尝试使用Java 7和8.
归档时间: |
|
查看次数: |
103198 次 |
最近记录: |