Java中的迭代器与 Foreach
背景 :
迭代器是集合框架提供的一个接口,用于遍历集合和对集合中的项目进行顺序访问。
// Iterating over collection 'c' using iterator
for (Iterator i = c.iterator(); i.hasNext(); )
System.out.println(i.next());
For each loop 用于遍历集合中的项目。
// Iterating over collection 'c' using for-each
for (Element e: c)
System.out.println(e);
我们将 for-each 循环中使用的 ':' 读作“in”。所以循环读作“对于元素中的每个元素e”,这里的元素是存储元素类型项目的集合。
注意:在使用 lambda 表达式的Java 8 中,我们可以简单地将 for-each 循环替换为
elements.forEach (e -> System.out.println(e) );
两次遍历的区别
在for-each循环中,我们不能修改collection,它会抛出一个ConcurrentModificationException,而iterator我们可以修改collection。
修改集合只是意味着删除一个元素或更改存储在集合中的项目的内容。发生这种情况是因为 for-each 循环隐式创建了一个迭代器,但它没有暴露给用户,因此我们无法修改集合中的项目。
什么时候使用哪个遍历?
- 如果我们必须修改集合,我们可以使用迭代器。
- 在使用嵌套 for 循环时,最好使用 for-each 循环,请考虑以下代码以更好地理解。
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 l = new LinkedList();
// 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 s=new LinkedList();
s.add(7);
s.add(8);
s.add(9);
// Iterator to iterate over a Link List
for (Iterator itr1=l.iterator(); itr1.hasNext(); )
{
for (Iterator itr2=s.iterator(); itr2.hasNext(); )
{
if (itr1.next() < itr2.next())
{
System.out.println(itr1.next());
}
}
}
}
}
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 l=new LinkedList();
// 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 s=new LinkedList();
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
输出:
Exception in thread "main" java.util.NoSuchElementException
at java.util.LinkedList$ListItr.next(LinkedList.java:888)
at Main.main(Main.java:29)
上面的代码抛出Java.util.NoSuchElementException。
在上面的代码中,我们为 itr1(即,对于 List l)一次又一次地调用 next() 方法。现在我们正在推进迭代器,甚至不检查集合中是否还有更多元素(在内部循环中),因此我们推进迭代器的数量超过了集合中的元素数量,这会导致 NoSuchElementException。
for-each 循环是为嵌套循环量身定制的。用下面的代码替换迭代器代码。
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 l=new LinkedList();
// 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 s=new LinkedList();
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
输出:
2 2 2 3 3 3 4 4
性能分析
使用 for-each 循环或迭代器遍历集合可提供相同的性能。在这里,我们所说的性能是指这两种遍历的时间复杂度。
如果您使用旧式 C for 循环进行迭代,那么我们可能会大大增加时间复杂度。
// 这里l是List,可以是ArrayList/LinkedList,n是List的大小
for (i=0;i
在这里,如果列表 l 是一个 ArrayList,那么我们可以在 O(1) 时间内访问它,因为它被分配了连续的内存块(就像一个数组一样),即可以进行随机访问。但是如果集合是 LinkedList,那么随机访问是不可能的,因为它没有分配连续的内存块,所以为了访问一个元素,我们必须遍历链接列表直到你到达所需的索引,因此花费的时间访问元素的最坏情况将是 O(n)。
对于没有随机访问的集合,迭代器和 for-each 循环比简单的 for 循环更快,而在允许随机访问的集合中,for-each 循环/for 循环/迭代器没有性能变化。
相关文章:
Java中的迭代器
在Java中从集合中检索元素(For-each、Iterator、ListIterator 和 EnumerationIterator)
参考:
https://docs.oracle.com/javase/8/docs/technotes/guides/language/foreach.html
https://docs.oracle.com/javase/7/docs/api/java Java
https://stackoverflow.com/questions/2113216/which-is-more-efficient-a-for-each-loop-or-an-iterator