我们可以使用for-each循环来迭代Iterator类型的对象吗?

如果我们执行以下操作,则会收到错误:

class FGH{ public static Iterator reverse(List list) { Collections.reverse(list); return list.iterator(); } public static void main(String[] args) { List list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); /*for(Iterator it:reverse(list)) Iterator it=reverse(list);*/ for (Object obj: reverse(list)) System.out.print(obj + ", ");}} 

但是如果我们像这样修改代码我们就不会得到错误,那么它是否意味着我们不能迭代Iterator类型的对象? :

 class FGH{ public static Iterator reverse(List list) { Collections.reverse(list); return list.iterator(); } public static void main(String[] args) { List list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); Iterator it=reverse(list); while(it.hasNext()){ Object obj=it.next(); System.out.println(obj); } }} 

第一个示例中的for循环期望reverse(list)Iterator的集合,当然它不是。 这就是为什么这个例子不起作用的原因。

通常,您只能在实现Iterable类上使用foreachIterator不是这些类中的一个。

请参见http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Iterable.html

很多答案都讨论迭代器不是迭代的。 这是真的,但这样的答案并未触及原因。

每个循环需要一个iterable的原因是允许多次遍历同一个对象(这样你就可以在同一个对象上使用多个for-each循环而不会出现意外行为),而迭代器只允许一次遍历。 如果for-each允许使用迭代器,那么在运行循环后没有意识到迭代器会耗尽的程序员的行为会令人惊讶。

如果您使用的API仅提供迭代器,并且您希望使用iterables,则有两种方法可以解决此问题:

  1. 创建一个匿名的可迭代类,其iterator()方法调用返回迭代器的API函数。 这样,每次在可迭代对象上使用for-each循环时,都会再次调用该API函数,返回一个新的(并且未经过调用的)迭代器。
  2. 创建一个可通过迭代的包装类,它接受一个迭代器并允许一次调用iterator() 。 在后续调用中,根据需要抛出AssertionErrorIllegalStateException

您将以这种方式使用增强型for循环:

 for (Object o : list) 

如上所述,您需要在for-each块中引用Iterable(或数组)。 例如,执行以下操作时:

 Collection coll = ...; for (String str : coll) { ... } 

以下是真正发生的事情:

 Collection coll = ...; for (Iterator iter = coll.iterator(); iter.hasNext(); ) { String str = iter.next(); } 

为了能够这样做,参数必须实现Iterable (例如,有一个返回Iterator (或者是一个数组)的公共iterator()方法。所以你的代码应如下所示:

 class FGH { public static void main(String[] args) { List list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); while (Object obj : Collections.reverse(list)){ System.out.println(obj); } } } 

“for each”语法是为集合设计的( Iterable是精确的),而不是Iterators。 我试图找出为什么Java在这个问题中以这种方式被设计的论点。

最简单的解决方案是返回反向列表(可迭代)而不是列表迭代器。 然后您可以使用简写for循环语法。

在前面提到的问题中概述了一种hackish方法,使用将Iterator包装为Iterable的Adapter类,并在第一次调用iterator()返回Iterator 。 看看适配器代码,它非常简单。 它用于此目的,但由于迭代器只能使用一次,因此它有点无效Iterable (它不能生成第二个迭代器)。

当您使用它两次时,会显示关键行为差异:

 for(Object a : foo) { } for(Object a : foo) { } 

如果它是一个正确的Iterable ,它将处理foo中的所有元素两次 ,但如果它使用我绘制的适配器,则只处理一次 – 第二个循环将不执行任何操作。

您必须首先将Iterator包装在Iterable 。 这是一个Java 8解决方案:

 for (Object obj : (Iterable) () -> reverse(list)) System.out.print(obj + ", "); 

或者,只需使用Iterator.forEachRemaining()

 reverse(list).forEachRemaining(obj -> System.out.print(obj + ", "));