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

时间:2010-01-29 15:28:20

标签: java 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);
     }
     }}

6 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:4)

很多答案都谈到迭代器不是迭代的。这是真的,但这样的答案并不涉及原因。

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

如果你使用的API只提供迭代器,并且你想使用iterables,你有两种方法可以解决这个问题:

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

答案 2 :(得分:0)

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

for (Object o : list)

答案 3 :(得分:0)

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

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

以下真的正在发生:

Collection<String> coll = ...;
for (Iterator<String> 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);
     }
  }
}

答案 4 :(得分:0)

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

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

question mentioned earlier中概述了一种hackish方式,使用将Iterator包装为Iterable的Adapter类,并在{{1}的第一次调用时返回Iterator 1}}。看看适配器代码,它非常简单。它起到了作用,但由于迭代器只能使用一次,因此它有点无效iterator()(它不能生成第二个迭代器)。

两次使用时会出现关键行为差异:

Iterable

将处理foo 中的所有元素如果它是正确的for(Object a : foo) { } for(Object a : foo) { } ,但只有一次如果它正在使用我绘制的适配器 - 第二个循环什么都不做。

答案 5 :(得分:0)

您必须先将Iterator包裹在Iterable中。这是Java 8解决方案:

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

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

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