迭代器vs
我在采访中被问到使用迭代器使用for循环的优点是什么,或者使用循环迭代器有什么优势?
任何机构都可以回答,以便将来如果我面临类似的问题,那么我可以回答
首先,有两种for循环,其行为非常不同。 一个使用索引:
for (int i = 0; i < list.size(); i++) { Thing t = list.get(i); ... }
这种循环并不总是可能的。 例如,列表有索引,但集合不是,因为它们是无序的集合。
另一个,foreach循环在幕后使用了一个Iterator:
for (Thing thing : list) { ... }
这适用于每种Iterable集合(或数组)
最后,您可以使用Iterator,它也适用于任何Iterable:
for (Iterator<Thing> it: list.iterator(); it.hasNext(); ) { Thing t = it.next(); ... }
所以你实际上有3个循环来比较。
你可以用不同的术语来比较它们:性能,可读性,容易出错,能力。
迭代器可以做一些foreach循环不能做的事情。 例如,如果迭代器支持迭代,则可以在迭代时删除元素:
for (Iterator<Thing> it: list.iterator(); it.hasNext(); ) { Thing t = it.next(); if (shouldBeDeleted(thing) { it.remove(); } }
列表还提供了可以在两个方向上迭代的迭代器。 一个foreach循环只能从开始到结束迭代。
但是迭代器更危险,可读性更差。 当你需要一个foreach循环时,它是最可读的解决scheme。 用一个迭代器,你可以做到以下,这将是一个错误:
for (Iterator<Thing> it: list.iterator(); it.hasNext(); ) { System.out.println(it.next().getFoo()); System.out.println(it.next().getBar()); }
foreach循环不允许发生这样的错误。
使用索引访问元素对于由数组支持的集合稍微有效一些。 但是,如果你改变了主意,并使用LinkedList而不是ArrayList,那么突然性能会变得糟糕,因为每次访问list.get(i)
,链表将不得不循环所有元素直到第i个元素。 一个迭代器(也就是foreach循环)没有这个问题。 它始终使用最好的方式遍历给定集合的元素,因为集合本身具有自己的Iterator实现。
我的一般经验是:使用foreach循环,除非你真的需要迭代器的function。 当我需要访问循环内的索引时,我只会使用带有数组索引的for循环。
如果您通过数字访问数据(例如“我”),则在使用数组时速度很快。 因为它直接去元素
但是,其他数据结构(如树,列表)需要更多的时间,因为它从第一个元素开始到目标元素。 当你使用列表。 它需要时间O(n)。 所以,这是缓慢的。
如果你使用迭代器,编译器知道你在哪里。 所以它需要O(1)(因为它从当前位置开始)
最后,如果你只使用支持直接访问的数组或数据结构(例如java中的arraylist)。 “a [i]”是好的。 但是,当你使用其他数据结构时,迭代器效率更高
迭代器优势:
- 能够从集合中删除元素。
- 能够使用
next()
和previous()
向前和向后移动。 - 能够通过使用
hasNext()
来检查是否有更多的元素。
Loop只是为了遍历一个Collection
而devise的,所以如果你只想迭代一个Collection
,最好使用for-Each
等循环,但是如果你想要更多的话可以使用Iterator。
Iterator和经典的for循环之间的主要区别在于,除了显式的访问迭代的项目的索引之外,使用Iterator从底层的集合实现中抽象客户端代码,允许我阐述。
当你的代码使用迭代器,无论是在这种forms
for(Item element : myCollection) { ... }
这个表格
Iterator<Item> iterator = myCollection.iterator(); while(iterator.hasNext()) { Item element = iterator.next(); ... }
或这种forms
for(Iterator iterator = myCollection.iterator(); iterator.hasNext(); ) { Item element = iterator.next(); ... }
你的代码所说的是“我不关心集合的types及其实现,我只关心我可以遍历其元素”。 这通常是更好的方法,因为它使您的代码更加分离。
另一方面,如果你使用经典的for循环,如
for(int i = 0; i < myCollection.size(); i++) { Item element = myCollection.get(i); ... }
你的代码说,我需要知道集合的types,因为我需要以特定的方式遍历它的元素,我也可能会检查空值或基于迭代次序计算一些结果。 这使得你的代码更加脆弱,因为如果在任何时候你收到的集合的types都发生了变化,它将会影响你的代码的工作方式。
综上所述,差异不在于速度或内存使用,而是关于解耦您的代码,以便更灵活地应对更改。
使用汽车,地铁或者你的Vespa去上class有什么不同? 在下雨的时候,汽车是有用的,当你不得不随身携带大件物品时,你会花费很多时间在交通上,这是污染。 地铁真棒,因为你不必关心道路,交通,污染,但它拥挤,你(可能)不会find一个座位,如果你想携带你的东西,它不能太大。 韦斯帕速度快,有趣,但是你不能在冬天或下雨的时候使用它,你不能随身携带大件物品,也会造成污染,而且交通非常危险。
什么是更好的? 没有独特的答案,这取决于情况,因为目标(上class)是一样的。 你必须确切地知道什么是环境条件,你必须携带什么等等。
迭代器与循环相同。 在一种情况下,您可以使用一些可见的结构元素; 在另一种情况下,你没有看到他们,但你有一个更紧凑的看法。 所以你必须根据环境条件来评估哪一个更好,你必须携带什么等:)