Java:为什么不能遍历迭代器?

我读了为什么Java的Iterator不是Iterable? 为什么不是可以输入的枚举? ,但我仍然不明白为什么这样:

void foo(Iterator it) { for (X x : it) { bar(x); baz(x); } } 

没有成功。 换句话说,除非我遗漏了某些东西,否则上面可能是一个很好的有效语法糖:

 void foo(Iterator it) { for (X x; it.hasNext();) { x = it.next(); bar(x); baz(x); } } 

但我仍然不明白为什么这个[…]不可能实现。

我可以看到几个原因:

  1. Iterator不是可重用的,所以for / each会消耗迭代器 – 也许不是不正确的行为,但对那些不知道for / each如何被去除的人来说是不直观的。
  2. Iterator在代码中看起来并不是“赤裸裸”,因此它会使JLS变得很复杂而且收益很小(for / each构造很糟糕,因为它在Iterable和数组上工作)。
  3. 有一个简单的解决方法 。 为此分配一个新对象似乎有点浪费,但分配很便宜,逃避分析在大多数情况下甚至可以消除你的成本。 (为什么他们没有在Iterables实用程序类中包含此解决方法,类似于CollectionsArrays ,但是在我之外。)
  4. (可能不正确 – 请参阅注释。) 我似乎记得JLS只能引用java.lang [需要引证] ,因此他们必须在java.lang java.util.Iterator创建一个Iterator接口,其中java.util.Iterator延伸而不添加任何内容。 现在我们有两个function相当的迭代器接口。 使用裸迭代器的新代码的50%将选择java.lang版本,其余使用java.util 随之而来的是混乱,兼容性问题比比皆是等等。

我认为第1-3点与Java语言设计理念似乎非常一致:不要让新手感到惊讶,如果它没有明显的收益来掩盖成本,请不要使规范复杂化,并且不要使用语言function可以使用库来完成。

相同的参数可以解释为什么java.util.Enumeration也不是Iterable

最有可能的原因是因为迭代器不可重复使用; 每次想要迭代元素时,你需要从Iterable集合中获得一个新的Iterator。 但是,作为快速修复:

 private static  Iterable iterable(final Iterator it){ return new Iterable(){ public Iterator iterator(){ return it; } }; } //.... { // ... // Now we can use: for ( X x : iterable(it) ){ // do something with x } // ... } //.... 

也就是说,最好的办法就是绕过Iterable接口而不是Iterator

for(Type t : iterable)语法仅对实现Iterable类有效。

迭代器不实现iterable。

您可以迭代CollectionListSet因为它们实现了Iterable。

以下代码是等效的:

 for (Type t: list) { // do something with t } 

 Iterator iter = list.iterator(); while (iter.hasNext()) { t = iter.next(); // do something with t } 

这是不可能的原因,因为for-each语法被添加到语言中以抽象出Iterator 。 使for-each循环与迭代器一起工作将无法实现for-each循环的创建。

实际上,你可以。

java 8上有很短的解决方法:

 for (X item : (Iterable) () -> iterator) 

有关该技巧的详细说明,请参见如何使用java 8流上的foreach循环进行迭代 。

并且在相关问题中可以找到一些解释为什么这不是原生支持的:

为什么Stream 没有实现Iterable

迭代器并不意味着可以重用(即:在多个迭代循环中使用)。 特别是, Iterator.hasNext()保证您可以安全地调用Iterator.next()并确实从底层集合中获取下一个值。

当在两个并发运行的迭代中使用相同的迭代器时(让我们假设一个multithreading场景),不再保留这个承诺:

 while(iter.hasNext() { // Now a context switch happens, another thread is performing // iter.hasNext(); x = iter.next(); String s = iter.next(); // A runtime exception is thrown because the iterator was // exhausted by the other thread } 

这种情况完全破坏了迭代器提供的协议。 实际上,它们甚至可以在单个线程程序中出现:迭代循环调用另一个使用相同迭代器执行自己的迭代的方法。 当此方法返回时,调用者正在发出Iterator.next()调用,该调用再次失败。

因为for-each被设计为如下所示:

 for each element of [some collection of elements] 

Iterator不是[some collection of elements] 。 一个数组和一个Iterable