为什么 Java 的 Iterator 不是 Iterable?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/839178/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:04:16  来源:igfitidea点击:

Why is Java's Iterator not an Iterable?

javaiteratoriterable

提问by ?ukasz Bownik

Why does the Iteratorinterface not extend Iterable?

为什么Iterator接口不扩展Iterable

The iterator()method could simply return this.

iterator()方法可以简单地返回this

Is it on purpose or just an oversight of Java's designers?

它是故意的还是只是 Java 设计者的疏忽?

It would be convenient to be able to use a for-each loop with iterators like this:

能够将 for-each 循环与这样的迭代器一起使用会很方便:

for(Object o : someContainer.listSomeObjects()) {
    ....
}

where listSomeObjects()returns an iterator.

wherelistSomeObjects()返回一个迭代器。

采纳答案by PaulJWilliams

Because an iterator generally points to a single instance in a collection. Iterable implies that one may obtain an iterator from an object to traverse over its elements - and there's no need to iterate over a single instance, which is what an iterator represents.

因为迭代器通常指向集合中的单个实例。Iterable 意味着可以从对象获取迭代器以遍历其元素 - 并且不需要迭代单个实例,这就是迭代器所代表的。

回答by Jon Skeet

An iterator is stateful. The idea is that if you call Iterable.iterator()twice you'll get independentiterators - for most iterables, anyway. That clearly wouldn't be the case in your scenario.

迭代器是有状态的。这个想法是,如果你调用Iterable.iterator()两次,你会得到独立的迭代器——无论如何,对于大多数迭代器。在您的场景中显然不是这种情况。

For example, I can usually write:

例如,我通常可以这样写:

public void iterateOver(Iterable<String> strings)
{
    for (String x : strings)
    {
         System.out.println(x);
    }
    for (String x : strings)
    {
         System.out.println(x);
    }
}

That should print the collection twice - but with your scheme the second loop would always terminate instantly.

这应该打印集合两次 - 但是使用您的方案,第二个循环将始终立即终止。

回答by dfa

For the sake of simplicity, Iterator and Iterable are two distinct concepts, Iterable is simply a shorthand for "I can return an Iterator". I think that your code should be:

为了简单起见,Iterator 和 Iterable 是两个截然不同的概念,Iterable 只是“我可以返回一个迭代器”的简写。我认为你的代码应该是:

for(Object o : someContainer) {
}

with someContainer instanceof SomeContainer extends Iterable<Object>

与 someContainer instanceof SomeContainer extends Iterable<Object>

回答by Martin Vatshelle

I also see many doing this:

我也看到很多人这样做:

public Iterator iterator() {
    return this;
}

But that does not make it right! This method would not be what you want!

但这并不能说明问题!这种方法不会是你想要的!

The method iterator()is supposed to return a new iterator starting from scratch. So one need to do something like this:

该方法iterator()应该从头开始返回一个新的迭代器。所以一个人需要做这样的事情:

public class IterableIterator implements Iterator, Iterable {

  //Constructor
  IterableIterator(SomeType initdata)
  {
    this.initdata = iter.initdata;
  }
  // methods of Iterable

  public Iterator iterator() {
    return new IterableIterator(this.intidata);
  }

  // methods of Iterator

  public boolean hasNext() {
    // ...
  }

  public Object next() {
    // ...
  }

  public void remove() {
    // ...
  }
}

The question is: would there be any way to make an abstract class performing this? So that to get an IterableIterator one only need to implement the two methods next() and hasNext()

问题是:有没有办法让抽象类执行此操作?所以要得到一个 IterableIterator 只需要实现 next() 和 hasNext() 两个方法

回答by Catweazle

As an aside: Scala has a toIterable() method in Iterator. See scala implicit or explicit conversion from iterator to iterable

顺便说一句:Scala 在 Iterator 中有一个 toIterable() 方法。请参阅从迭代器到可迭代的 scala 隐式或显式转换

回答by Barney

For my $0.02, I completely agree that Iterator should not implement Iterable, but I think the enhanced for loop should accept either. I think the whole "make iterators iterable" argument comes up as a work around to a defect in the language.

对于我的 0.02 美元,我完全同意 Iterator 不应该实现 Iterable,但我认为增强的 for 循环也应该接受。我认为整个“使迭代器可迭代”的论点都是为了解决语言中的缺陷。

The whole reason for the introduction of the enhanced for loop was that it "eliminates the drudgery and error-proneness of iterators and index variables when iterating over collections and arrays" [1].

引入增强的 for 循环的全部原因是它“在迭代集合和数组时消除了迭代器和索引变量的繁琐和容易出错的问题”[ 1]。

Collection<Item> items...

for (Iterator<Item> iter = items.iterator(); iter.hasNext(); ) {
    Item item = iter.next();
    ...
}

for (Item item : items) {
    ...
}

Why then does this same argument not hold for iterators?

为什么同样的论点不适用于迭代器?

Iterator<Iter> iter...
..
while (iter.hasNext()) {
    Item item = iter.next();
    ...
}

for (Item item : iter) {
    ...
}

In both cases, the calls to hasNext() and next() have been removed, and there is no reference to the iterator in the inner loop. Yes, I understand that Iterables can be re-used to create multiple iterators, but that all happens outside of the for loop: inside the loop there is only ever a forward progression one item at a time over the items returned by the iterator.

在这两种情况下,对 hasNext() 和 next() 的调用都已删除,并且在内循环中没有对迭代器的引用。是的,我知道可重复使用 Iterables 来创建多个迭代器,但这一切都发生在 for 循环之外:在循环内部,迭代器返回的项目一次只有一个项目向前推进。

Also, allowing this would also make it easy to use the for loop for Enumerations, which, as has been pointed out elsewhere, are analogous to Iterators not Iterables.

此外,允许这样做也可以很容易地为枚举使用 for 循环,正如在别处指出的那样,它类似于迭代器而不是迭代器。

So don't make Iterator implement Iterable, but update the for loop to accept either.

所以不要让 Iterator 实现 Iterable,而是更新 for 循环以接受。

Cheers,

干杯,

回答by McDowell

As pointed out by others, Iteratorand Iterableare two different things.

正如指出的别人,IteratorIterable是两个不同的东西。

Also, Iteratorimplementations predate enhanced for loops.

此外,Iterator实现早于增强的 for 循环。

It is also trivial to overcome this limitation with a simple adapter method that looks like this when used with static method imports:

使用一个简单的适配器方法来克服这个限制也是微不足道的,当与静态方法导入一起使用时,它看起来像这样:

for (String line : in(lines)) {
  System.out.println(line);
}

Sample implementation:

示例实现:

  /**
   * Adapts an {@link Iterator} to an {@link Iterable} for use in enhanced for
   * loops. If {@link Iterable#iterator()} is invoked more than once, an
   * {@link IllegalStateException} is thrown.
   */
  public static <T> Iterable<T> in(final Iterator<T> iterator) {
    assert iterator != null;
    class SingleUseIterable implements Iterable<T> {
      private boolean used = false;

      @Override
      public Iterator<T> iterator() {
        if (used) {
          throw new IllegalStateException("SingleUseIterable already invoked");
        }
        used = true;
        return iterator;
      }
    }
    return new SingleUseIterable();
  }


In Java 8 adapting an Iteratorto an Iterablegets simpler:

在 Java 8 中,将 an 适配Iterator到 anIterable变得更简单:

for (String s : (Iterable<String>) () -> iterator) {

回答by andrew cooke

As others have said, an Iterable can be called multiple times, returning a fresh Iterator on each call; an Iterator is used just once. So they are related, but serve different purposes. Frustratingly, however, the "compact for" method works only with an iterable.

正如其他人所说,一个 Iterable 可以被多次调用,每次调用都会返回一个新的 Iterator;Iterator 只使用一次。所以它们是相关的,但服务于不同的目的。然而令人沮丧的是,“compact for”方法仅适用于可迭代对象。

What I will describe below is one way to have the best of both worlds - returning an Iterable (for nicer syntax) even when the underlying sequence of data is one-off.

我将在下面描述的是一种两全其美的方法 - 即使底层数据序列是一次性的,也返回一个 Iterable(为了更好的语法)。

The trick is to return an anonymous implementation of the Iterable that actually triggers the work. So instead of doing the work that generates a one-off sequence and then returning an Iterator over that, you return an Iterable which, each time it is accessed, redoes the work. That might seem wasteful, but often you will only call the Iterable once anyway, and even if you do call it multiple times, it still has reasonable semantics (unlike a simple wrapper that makes an Iterator "look like" an Iterable, this won't fail if used twice).

诀窍是返回实际触发工作的 Iterable 的匿名实现。因此,与其执行生成一次性序列的工作,然后在其上返回迭代器,不如返回一个 Iterable,每次访问它时,都会重做该工作。这可能看起来很浪费,但通常你只会调用 Iterable 一次,即使你多次调用它,它仍然具有合理的语义(不像一个简单的包装器使迭代器“看起来像”一个可迭代的,这不会'如果使用两次不会失败)。

For example, say I have a DAO that provides a series of objects from a database, and I want to provide access to that via an iterator (eg. to avoid creating all objects in memory if they are not needed). Now I could just return an iterator, but that makes using the returned value in a loop ugly. So instead I wrap everything in an anon Iterable:

例如,假设我有一个从数据库提供一系列对象的 DAO,我想通过迭代器提供对它的访问(例如,避免在不需要时在内存中创建所有对象)。现在我可以只返回一个迭代器,但这使得在循环中使用返回值变得丑陋。因此,我将所有内容都包装在 anon Iterable 中:

class MetricDao {
    ...
    /**
     * @return All known metrics.
     */
    public final Iterable<Metric> loadAll() {
        return new Iterable<Metric>() {
            @Override
            public Iterator<Metric> iterator() {
                return sessionFactory.getCurrentSession()
                        .createQuery("from Metric as metric")
                        .iterate();
            }
        };
    }
}

this can then be used in code like this:

然后可以在这样的代码中使用它:

class DaoUser {
    private MetricDao dao;
    for (Metric existing : dao.loadAll()) {
        // do stuff here...
    }
}

which lets me use the compact for loop while still keeping incremental memory use.

这让我可以使用紧凑的 for 循环,同时仍然保持增量内存使用。

This approach is "lazy" - the work is not done when the Iterable is requested, but only later when the contents are iterated over - and you need to be aware of the consequences of that. In the example with a DAO that means iterating over the results within the database transaction.

这种方法是“懒惰的”——在请求 Iterable 时不会完成工作,但只有在内容被迭代时才完成——并且您需要意识到这样做的后果。在带有 DAO 的示例中,这意味着迭代数据库事务中的结果。

So there are various caveats, but this can still be a useful idiom in many cases.

所以有各种警告,但在许多情况下这仍然是一个有用的习语。

回答by Sakthi King

You can try the following example :

您可以尝试以下示例:

List ispresent=new ArrayList();
Iterator iterator=ispresent.iterator();
while(iterator.hasNext())
{
    System.out.println(iterator.next());
}

回答by Fabrizio

On a related note, you may find the IteratorIterable adapter in Apache Commons Collections4 useful. Just create an instance from an iterator, and you have the corresponding iterable.

在相关说明中,您可能会发现 Apache Commons Collections4 中的 IteratorIterable 适配器很有用。只需从迭代器创建一个实例,您就拥有相应的可迭代对象。

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html

https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html

ID: org.apache.commons:commons-collections4:4.0

ID:org.apache.commons:commons-collections4:4.0