传统for循环与Java中的Iterator / foreach的性能
在遍历ArrayList,HashMap和其他集合时比较传统的for循环与Iterator是否有任何性能测试结果可用?
或者干脆为什么我应该使用Iterator over循环,反之亦然?
假设这是你的意思:
// traditional for loop
for (int i = 0; i < collection.size(); i++) {
T obj = collection.get(i);
// snip
}
// using iterator
Iterator<T> iter = collection.iterator();
while (iter.hasNext()) {
T obj = iter.next();
// snip
}
// using iterator internally (confirm it yourself using javap -c)
for (T obj : collection) {
// snip
}
对于没有随机访问的集合(例如TreeSet,HashMap,LinkedList),迭代器速度更快。 对于数组和ArrayLists,性能差异应该可以忽略不计。
编辑:我相信微观基准是非常邪恶的根源,就像早期的优化一样。 但是,我认为,对于这些相当琐碎的事情的影响感觉很好。 因此我运行了一个小测试:
结果对于所有人来说都是相似的,但是对于使用LinkedList的“with with counter”。 所有其他五个都花了不到20毫秒来遍历整个列表。 在LinkedList上使用list.get(i)
100,000次完成超过2分钟(!)(慢60,000次)。 哇! :)因此,最好使用迭代器(明确或隐含地为每个迭代器使用),特别是如果您不知道处理的列表的类型和大小。
使用迭代器的第一个理由显然是正确的。 如果您使用手动索引,则可能会出现非常无害的逐个错误,只有仔细观察才能看到:您是从1还是从0开始? 你有没有完成length - 1
? 你使用<
或<=
? 如果您使用迭代器,则更容易发现它实际上迭代了整个数组。 “说出你的所作所为,按照你的意思行事。”
第二个原因是统一访问不同的数据结构。 一个数组可以通过索引有效地访问,但是链接列表最好通过记住最后访问的元素来遍历(否则你会得到一个“Shlemiel画家”)。 哈希映射更加复杂。 通过提供来自这些数据结构和其他数据结构的统一接口(例如,您也可以进行树遍历),您将再次获得明显的正确性。 遍历逻辑必须仅实现一次,而使用它的代码可以简洁地“说出它做了什么,然后做它说的。”
性能在大多数情况下是相似的。
但是,每当一个代码收到一个List,并在其上循环时,就有一个众所周知的情况:
对于所有不实现RandomAccess的List实现 (例如:LinkedList) ,Iterator更好 。
原因在于对于这些列表,按索引访问元素不是一个常量时间操作。
所以你也可以认为迭代器更加健壮(实现细节)。
一如既往,性能不应该成为隐藏可读性问题。
java5的foreach循环在这方面很受欢迎:-)
上一篇: Performance of traditional for loop vs Iterator/foreach in Java