背景: 迭代器 是集合框架提供的一个接口,用于遍历集合并对集合中的项进行顺序访问。
// Iterating over collection 'c' using iterator for (Iterator i = c.iterator(); i.hasNext(); ) System.out.println(i.next());
每人 循环用于遍历集合中的项。
// Iterating over collection 'c' using for-each for (Element e: c) System.out.println(e);
我们将每个循环中使用的“:”读作“in”。所以循环读作“对于元素中的每个元素e”,这里的元素是存储元素类型项的集合。
注: 在使用lambda表达式的Java8中,我们可以简单地用
elements.forEach (e -> System.out.println(e) );
两次遍历之间的差异 在for each循环中,我们不能修改集合,它将抛出一个 ConcurrentModificationException 另一方面,通过迭代器,我们可以修改集合。
修改集合只意味着删除集合中存储的元素或更改其内容。这是因为for each循环隐式地创建了一个迭代器,但它不向用户公开,因此我们无法修改集合中的项。
何时使用哪种遍历?
- 如果我们必须修改集合,我们可以使用迭代器。
- 在使用嵌套for循环时,最好使用每个循环,考虑下面的代码以更好地理解。
JAVA
// Java program to demonstrate working of nested iterators // may not work as expected and throw exception. import java.util.*; public class Main { public static void main(String args[]) { // Create a link list which stores integer elements List<Integer> l = new LinkedList<Integer>(); // Now add elements to the Link List l.add( 2 ); l.add( 3 ); l.add( 4 ); // Make another Link List which stores integer elements List<Integer> s= new LinkedList<Integer>(); s.add( 7 ); s.add( 8 ); s.add( 9 ); // Iterator to iterate over a Link List for (Iterator<Integer> itr1=l.iterator(); itr1.hasNext(); ) { for (Iterator<Integer> itr2=s.iterator(); itr2.hasNext(); ) { if (itr1.next() < itr2.next()) { System.out.println(itr1.next()); } } } } } |
输出:
Exception in thread "main" java.util.NoSuchElementException at java.util.LinkedList$ListItr.next(LinkedList.java:888) at Main.main(Main.java:29)
上面的代码抛出了java。util。没有什么例外。
在上面的代码中,我们一次又一次地调用itr1的next()方法(即List l)。现在,我们正在推进迭代器,甚至没有检查它在集合(在内部循环中)中是否还有更多元素,因此,我们推进迭代器的速度超过了集合中的元素数量,这导致了NoTouchElementException。
每个循环都是为嵌套循环量身定制的。用下面的代码替换迭代器代码。
JAVA
// Java program to demonstrate working of nested for-each import java.util.*; public class Main { public static void main(String args[]) { // Create a link list which stores integer elements List<Integer> l= new LinkedList<Integer>(); // Now add elements to the Link List l.add( 2 ); l.add( 3 ); l.add( 4 ); // Make another Link List which stores integer elements List<Integer> s= new LinkedList<Integer>(); s.add( 2 ); s.add( 4 ); s.add( 5 ); s.add( 6 ); // Iterator to iterate over a Link List for ( int a:l) { for ( int b:s) { if (a<b) System.out.print(a + " " ); } } } } |
输出:
2 2 2 3 3 3 4 4
性能分析
使用for-each循环或迭代器遍历集合可以获得相同的性能。这里,性能指的是这两种遍历的时间复杂度。
如果您使用老式的C for循环进行迭代,那么我们可能会大幅增加时间复杂度。 //这里l是列表,它可以是ArrayList/LinkedList,n是列表的大小
for (i=0;i<n;i++) System.out.println(l.get(i));
这里,如果列表l是ArrayList,那么我们可以在O(1)时间内访问它,因为它被分配了连续的内存块(就像一个数组),也就是说,随机访问是可能的。但是,如果集合是LinkedList,那么随机访问是不可能的,因为它没有分配连续的内存块,所以为了访问一个元素,我们必须遍历链接列表,直到到达所需的索引,因此在最坏的情况下访问一个元素所用的时间将是O(n)。
对于没有随机访问的集合,迭代器和for each循环比简单for循环快,而在允许随机访问的集合中,for each循环/for循环/迭代器的性能没有变化。
相关文章: Java中的迭代器 在Java中从集合中检索元素(针对每个元素、迭代器、ListIterator和EnumerationIterator) 参考资料: https://docs.oracle.com/javase/8/docs/technotes/guides/language/foreach.html https://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html https://stackoverflow.com/questions/2113216/which-is-more-efficient-a-for-each-loop-or-an-iterator
本文由 希拉格·阿加瓦尔 .如果你喜欢GeekSforgek,并且想贡献自己的力量,你也可以写一篇文章,并将文章邮寄到contribute@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写评论