Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中传统for循环与迭代器/foreach的性能比较_Java_Map_Iterator_Arraylist_For Loop - Fatal编程技术网

Java中传统for循环与迭代器/foreach的性能比较

Java中传统for循环与迭代器/foreach的性能比较,java,map,iterator,arraylist,for-loop,Java,Map,Iterator,Arraylist,For Loop,在遍历ArrayList、HashMap和其他集合时,比较传统的for循环和迭代器是否有性能测试结果 或者简单地说,为什么我应该在循环中使用迭代器,或者反过来使用迭代器?在生成的代码中使用或,您将看到没有真正的区别。新迭代器形式的优点是它在代码库中看起来更干净 编辑:我从其他答案中看出,您实际上指的是使用geti与迭代器之间的区别。我把最初的问题理解为使用迭代器的新旧方法之间的区别 使用geti并维护自己的计数器,特别是对于列表类,这不是一个好主意,原因在公认的答案中提到。假设这就是您的意思:

在遍历ArrayList、HashMap和其他集合时,比较传统的for循环和迭代器是否有性能测试结果

或者简单地说,为什么我应该在循环中使用迭代器,或者反过来使用迭代器?

在生成的代码中使用或,您将看到没有真正的区别。新迭代器形式的优点是它在代码库中看起来更干净

编辑:我从其他答案中看出,您实际上指的是使用geti与迭代器之间的区别。我把最初的问题理解为使用迭代器的新旧方法之间的区别


使用geti并维护自己的计数器,特别是对于列表类,这不是一个好主意,原因在公认的答案中提到。

假设这就是您的意思:

// 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)更快。对于数组和ArrayList,性能差异应该可以忽略不计

编辑:我相信微观基准测试是非常邪恶的根源,就像早期优化一样。但是,再一次,我认为对这些非常琐碎的事情的含义有一种感觉是很好的。因此我跑:

分别迭代LinkedList和ArrayList 有100000个随机字符串 把它们的长度加起来只是为了避免编译器优化掉整个循环 使用所有3种循环样式迭代器,对于每个循环样式,对于带有计数器的循环样式
除带有LinkedList的with counter外,所有的结果都类似。所有其他五个都用了不到20毫秒的时间遍历整个列表。在LinkedList上使用list.geti 100000次,耗时超过2分钟!以慢60000倍的速度完成。哇因此,最好显式或隐式地使用迭代器for each,特别是当您不知道要处理的列表的类型和大小时

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

但是,每当代码接收到列表并在其上循环时,就会出现一种众所周知的情况: 迭代器对于所有不实现RandomAccess的列表实现来说都要好得多,例如:LinkedList

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

这样,您也可以将迭代器视为对实现细节更健壮。

和往常一样,性能不应该被忽略,因为它隐藏了可读性问题。
java5foreach循环在这方面非常成功:-

在i++语法中使用迭代器的最佳原因之一是,并非所有的数据结构都支持随机访问,更不用说它的性能了。您还应该对列表或集合接口进行编程,这样,如果您以后决定另一个数据结构将更有效,您就可以在不进行大规模手术的情况下将其交换出去。在这种情况下,编码到接口的情况下,您不一定知道实现细节,而将其推迟到数据结构本身可能更明智

我学会坚持使用for-each的原因之一是它简化了嵌套循环,尤其是在2+维循环上。所有的i、j和k都可能会很快变得混乱。

使用迭代器的第一个原因是明显的正确性。如果您使用手动索引,可能会出现一些非常无害的off-by-one错误,只有仔细观察才能看到这些错误:您是从1开始还是从0开始?你最终以-1结束了吗?你用了+1来解释斯福塞内格尔说的话了吗。仅供参考,无论您使用显式迭代器还是隐式迭代器(即for each),都不会产生性能差异,因为它们编译为相同的字节码

我不相信

for (T obj : collection) {
计算。每次通过循环时的大小,因此比

for (int i = 0; i < collection.size(); i++) {

是的,它确实对不是像LinkedList那样基于随机访问的集合产生了影响。内部链表由指向下一个的节点实现,从头部节点开始

链表中的geti方法从head节点开始,通过链接一直导航到第i个节点。当您使用传统的for循环在链表上迭代时,每次都会从head节点重新开始,因此整体遍历将变成二次遍历

for( int i = 0; i< list.size(); i++ ) {
    list.get(i); //this starts everytime from the head node instead of previous node
}

谢谢,但是ArrayList呢?ArrayList实现了随机访问,因此list.geti速度很快。性能差异应该可以忽略不计。注意:虽然我不知道JDK中的LinkedList是否是以这种方式编写的,但如果编写一个LinkedList实现,其中传统的for循环将以与随机访问一样快的速度执行,那将是微不足道的。所有需要做的就是保留一个内部指针,指向请求随机访问的最后一个元素。这看起来像是一个微不足道的实现,它会加速太多的代码,以至于我无法想象它不在其中。@tster:实际上迭代器就是这样做的。你的链接列表r
esult显示了当您从On转到On^2或更多时会发生什么其他五个在整个列表上迭代不到20毫秒的时间看起来像是JVM死代码优化开始了。。。LinkedList和ArrayList的迭代之间的差异对于ArrayList@bestsss不,当然没有。我已经生成了100000个随机字符串,实际上是UUID,并将它们的长度相加,在循环后打印到标准输出。当然,UUID具有相同的长度,这使得输出是可预测的,但是编译器没有那么聪明。信不信由你,但现代CPU可以在20毫秒内完成这一任务。换一个角度来看:我的CPU每个核心有4000个BogoMips。因此,我们谈论的是每秒数十亿条指令或每秒数百万条指令。因此,用数百万条指令迭代100000个字符串是可行的。CPU的速度比大多数开发人员想象的要快:总之,这是一个可行的选择,编译器除了疯狂地预取之外不会优化任何东西。这种情况也完全适合二级缓存,即使是带有LinkedList的缓存。如果不是所有元素都按顺序添加,则退出二级缓存将对LinkedList产生更大的影响。混合方式如何?迭代器iter=collection.Iterator;int l=collection.size;对于int i=0,ifor( Object item: list ) { //item element is obtained from the iterator's next method. }