【问题标题】:Can we use for-each loop for iterating the objects of Iterator type? [duplicate]我们可以使用 for-each 循环来迭代 Iterator 类型的对象吗? [复制]
【发布时间】:2011-01-10 21:34:45
【问题描述】:

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

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);
     }
     }}

【问题讨论】:

    标签: java iterator


    【解决方案1】:

    您必须先将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 + ", "));
    

    【讨论】:

      【解决方案2】:

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

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

      question mentioned earlier 中概述了一种骇人听闻的方式,使用将Iterator 包装为Iterable 的适配器类,并在第一次调用iterator() 时返回Iterator。查看适配器代码,它相当简单。它可以达到目的,但由于迭代器只能使用一次,所以它有点无效Iterable(它将无法产生第二个迭代器)。

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

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

      如果它是正确的Iterable,将处理 foo 中的所有元素 两次,但如果它使用的是我绘制的适配器,则只处理 一次 - 第二个循环将执行什么都没有。

      【讨论】:

        【解决方案3】:

        如上所述,您需要在 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】:

          很多答案都在谈论迭代器如何不是可迭代的。确实如此,但这样的答案并没有触及原因。

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

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

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

          【讨论】:

          • 不确定你在说什么 - 你怎么能在 for-each 循环中多次遍历一个可迭代对象?还是我误解了你的答案?
          • 不,我是说你不能有多个 for-each 循环都引用同一个迭代器对象;在第一个 for-each 循环之后,它会被耗尽(即使只是部分地,如果循环有 break 等)。
          • IterableIterator 包装器是一个可靠的解决方案(它实际上是我们所有项目中使用的实用程序 jar 的核心部分)。我怀疑他们没有让 Iterator 扩展 Iterable 的另一个原因是 b/c Iterator 是一个接口,在这一点上扩展它会破坏大量现有代码,或者强制另一个类似 Iterator 的接口(还记得 Enumeration 吗?)。
          • @Kevin:出于好奇,您的包装器是否也强制执行一次性约束,或者以其他方式记录这样的包装器只能迭代一次? [继续]
          【解决方案5】:

          您可以通过这种方式使用增强的 for 循环:

          for (Object o : list)
          

          【讨论】:

            【解决方案6】:

            第一个示例中的for 循环期望reverse(list)Iterator 的集合,当然不是。这就是该示例行不通的原因。

            一般来说,您只能在实现Iterable 的类上使用foreachIterator 不是这些类之一。

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-06-07
              • 1970-01-01
              • 2011-07-27
              • 1970-01-01
              • 2017-03-30
              • 2018-03-10
              相关资源
              最近更新 更多