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

noa*_*mtm 20 java iterator iterable

我读了为什么Java的迭代器不是Iterable?为什么不枚举可迭代?,但我仍然不明白为什么这样:

void foo(Iterator<X> it) {
  for (X x : it) {
    bar(x);
    baz(x);
  }
}
Run Code Online (Sandbox Code Playgroud)

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

void foo(Iterator<X> it) {
  for (X x; it.hasNext();) {
    x = it.next();
    bar(x);
    baz(x);
  }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*yan 19

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

private static <T> Iterable<T> iterable(final Iterator<T> it){
     return new Iterable<T>(){ public Iterator<T> iterator(){ return it; } };
}

//....
{
     // ...
     // Now we can use:
     for ( X x : iterable(it) ){
        // do something with x
     }
     // ...
}
//....
Run Code Online (Sandbox Code Playgroud)

也就是说,最好的办法就是简单地绕过Iterable<T>界面而不是Iterator<T>

  • @noamtm:如果它不是`Collection`但可以提供`Iterator`,那么它应该实现`Iterable`. (5认同)

gus*_*afc 9

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

我可以看到几个原因:

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

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

同样的论点也可以解释为什么java.util.Enumeration不是Iterable.


jjn*_*guy 6

for(Type t : iterable)语法仅适用于实现类Iterable<Type>.

迭代器不实现iterable.

您可以通过类似的事情重复Collection<T>,List<T>或者Set<T>是因为他们实现Iterable.

以下代码是等效的:

for (Type t: list) {
    // do something with t
}
Run Code Online (Sandbox Code Playgroud)

Iterator<Type> iter = list.iterator();
while (iter.hasNext()) {
    t = iter.next();
    // do something with t
}
Run Code Online (Sandbox Code Playgroud)

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

  • 很明显,它没有回答我的"为什么它不可能"的问题. (3认同)

Vad*_*zim 6

事实上,你可以。

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

for (X item : (Iterable<X>) () -> iterator)
Run Code Online (Sandbox Code Playgroud)

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

在相关问题中可以找到一些解释为什么这不被本地支持:

为什么 Stream<T> 没有实现 Iterable<T>?