Java中传统for循环与Iterator/foreach的性能

Har*_*ish 60 java iterator for-loop arraylist map

在遍历ArrayList,HashMap和其他集合时,是否有任何性能测试结果可用于比较传统的for循环与Iterator?

或者我为什么要使用Iterator for循环,反之亦然?

sfu*_*ger 81

假设这就是你的意思:

// 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
}
Run Code Online (Sandbox Code Playgroud)

对于没有随机访问的集合(例如TreeSet,HashMap,LinkedList),Iterator更快.对于数组和ArrayLists,性能差异应该可以忽略不计.

编辑:我相信微基准测试是非常邪恶的根源,就像早期优化一样.但话说回来,我觉得对这些相当琐碎的事情的影响感觉很好.因此,我进行了一个小测试:

  • 迭代地遍历LinkedList和ArrayList
  • 拥有100,000个"随机"字符串
  • 总结它们的长度(只是为了避免编译器优化掉整个循环)
  • 使用所有3个循环样式(迭代器,每个,用于计数器)

除了"with with counter"与LinkedList之外的所有结果都相似.所有其他五个花费不到20毫秒来迭代整个列表.使用list.get(i)上一个LinkedList 100,000次时间超过2分钟(!)来完成的(60,000倍慢).哇!:)因此,最好使用迭代器(显式或隐式使用每个),特别是如果你不知道你处理的列表的类型和大小.

  • 您的LinkedList结果显示从O(n)到O(n ^ 2)(或更多)时会发生什么 (13认同)

Sva*_*nte 22

使用迭代器的第一个原因是显而易见的正确性.如果您使用手动索引,可能会出现非常无害的逐个错误,只有在您仔细观察时才能看到这些错误:您是从1开始还是从0开始?你完成了length - 1吗?你使用<<=?如果使用迭代器,则更容易看出它实际上正在迭代整个数组."说你做什么,做你说的话."

第二个原因是对不同数据结构的统一访问.可以通过索引有效地访问数组,但最好通过记住访问的最后一个元素来遍历链接列表(否则您将获得" Shlemiel the painter ").哈希映射更复杂.通过提供来自这些和其他数据结构的统一接口(例如,您也可以进行树遍历),您可以再次获得明显的正确性.遍历逻辑必须只实现一次,使用它的代码可以简洁地"说出它做什么,并按照它说的做".


KLE*_*KLE 5

在大多数情况下,性能是相似的。

但是,每当代码接收到一个List并在其上循环时,就会发生一种众所周知的情况:
对于所有未实现RandomAccess的List实现,Iterator会更好(示例:LinkedList)。

原因是对于这些列表,按索引访问元素不是固定时间的操作。

因此,您也可以将Iterator视为更健壮的(针对实现细节)。


与往常一样,性能不应成为隐藏可读性的问题。
java5 foreach循环在这方面很受欢迎:-)

  • @tster:实际上,这正是迭代器所做的。 (2认同)