为什么Java的迭代器不是可迭代的?

为什么Iterator接口不能扩展Iterable

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

这是故意的还是仅仅是Javadevise师的疏忽?

能够像这样使用迭代器的for-each循环将是方便的:

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

其中listSomeObjects()返回一个迭代器。

因为迭代器通常指向集合中的单个实例。 可迭代意味着可以从一个对象获得一个迭代器来遍历它的元素 – 而且不需要遍历一个迭代器代表的实例。

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

例如,我通常可以写:

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

这应该打印收集两次 – 但与您的计划第二循环将永远终止即刻。

对于我的$ 0.02,我完全同意Iterator不应该实现Iterable,但我认为增强的for循环也应该接受。 我认为整个“使迭代器迭代”的论点成为解决语言缺陷的一个工具。

引入增强型for循环的全部原因是“在迭代集合和数组时,消除了迭代器和索引variables的困难和错误倾向”[ 1 ]。

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

那么为什么这个相同的论点不适用于迭代器呢?

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

在这两种情况下,对hasNext()和next()的调用都被删除,并且在内部循环中没有对迭代器的引用。 是的,我明白Iterables可以重用来创build多个迭代器,但是这一切都发生在for循环之外:在循环内部,迭代器只返回一个项目的一个项目。

另外,允许这样做也可以很容易地使用枚举的for循环,正如在其他地方已经指出的那样,类似于Iterators而不是Iterables。

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

干杯,

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

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

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

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

示例实现:

  /** * 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(); } 

在Java 8中,使Iterator适应Iterable变得更简单:

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

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

我将在下面描述的是获得两全其美的一种方法 – 即使在基本数据序列是一次性的情况下也返回Iterable(用于更好的语法)。

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

例如,假设我有一个从数据库中提供一系列对象的DAO,我想通过一个迭代器来提供对象的访问(例如,为了避免在内存中创build所有不需要的对象)。 现在我只能返回一个迭代器,但是这使得循环中的返回值变丑。 所以我把所有的东西都换成了一个可重用的:

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

这可以用于这样的代码:

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

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

这种方法是“懒惰”的 – 当Iterable被请求时,工作并没有完成,但是只有当内容被迭代时才会完成 – 而且你需要知道结果。 在DAO的例子中,这意味着迭代数据库事务中的结果。

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

Iterator是一个允许你迭代某个东西的接口。 它是通过某种types的集合来实现的。

Iterable是一个函数接口,它表示包含一个可访问的迭代器。

在Java8中,这使得生活变得非常简单…如果你有一个Iterator但是需要一个Iterable你可以简单地做:

 Iterator<T> someIterator; Iterable<T> = ()->someIterator; 

这也适用于for循环:

 for (T item : ()->someIterator){ //doSomething with item } 

令人难以置信的是,还没有人给出这个答案呢。 以下是如何使用新的Java 8 Iterator.forEachRemaining()方法“轻松”遍历Iterator

 Iterator<String> it = ... it.forEachRemaining(System.out::println); 

当然,有一个“简单”的解决scheme直接与foreach循环一起工作,将Iterator封装在一个Iterable lambda中:

 for (String s : (Iterable<String>) () -> it) System.out.println(s); 

我也看到很多这样做:

 public Iterator iterator() { return this; } 

但是,这并不正确! 这种方法不会是你想要的!

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

 public class IterableIterator implements Iterator, Iterable { //Constructor IterableIterator(IterableIterator iter) { this.initdata = iter.initdata; } // methods of Iterable public Iterator iterator() { return new MyClass(this.somedata); } // methods of Iterator public boolean hasNext() { // ... } public Object next() { // ... } public void remove() { // ... } } 

问题是:有没有办法让抽象类来执行这个? 为了得到一个IterableIterator,只需要实现next()和hasNext()两个方法,

如果你来这里寻找解决方法,你可以使用IteratorIterable 。 (适用于Java 1.6及更高版本)

示例用法(反转Vector)。

 import java.util.Vector; import org.apache.commons.collections4.iterators.IteratorIterable; import org.apache.commons.collections4.iterators.ReverseListIterator; public class Test { public static void main(String ... args) { Vector<String> vs = new Vector<String>(); vs.add("one"); vs.add("two"); for ( String s: vs ) { System.out.println(s); } Iterable<String> is = new IteratorIterable(new ReverseListIterator(vs)); for ( String s: is ) { System.out.println(s); } } } 

版画

 one two two one 

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

 for(Object o : someContainer) { } 

用SomeContainer instanceof SomeContainer extends Iterable<Object>

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

在相关说明中,您可能会发现Apache Commons Collections4中的IteratorIterable适配器很有用。 只要从一个迭代器创build一个实例,并且你有相应的迭代器。

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

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

迭代器是有状态的,它们有一个“下一个”元素,一旦迭代就会变得“枯竭”。 要查看问题出在哪里,请运行以下代码,打印多less个数字?

 Iterator<Integer> iterator = Arrays.asList(1,2,3).iterator(); Iterable<Integer> myIterable = ()->iterator; for(Integer i : myIterable) System.out.print(i); System.out.println(); for(Integer i : myIterable) System.out.print(i); 

我同意接受的答案,但是想添加我自己的解释。

  • 迭代器表示遍历的状态,例如,可以从迭代器中获取当前元素并向前移动到下一个元素。

  • Iterable表示可以遍历的集合,它可以根据需要返回尽可能多的迭代器,每个迭代器都代表自己的遍历状态,一个迭代器可能指向第一个元素,而另一个可能指向第三个元素。

如果Java for循环同时接受Iterator和Iterable,那将会很好。

你可以尝试下面的例子:

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