为什么Java不允许在迭代器上使用foreach(仅在iterables上)?

为什么Java不允许在迭代器上使用foreach(仅在iterables上)?,java,syntax,iterator,language-design,iterable,Java,Syntax,Iterator,Language Design,Iterable,可能重复: 据我所知,foreach循环是在Java5中添加的语法。所以 Iterable<O> iterable; for(O o : iterable) { // Do something } (这实际上是对Iterable API的一种丑陋的滥用,因为它只能迭代一次!) 如果它是围绕迭代器而不是iterable设计的,那么可以做很多有趣的事情: for(O o : iterable.iterator()) {} // Iterate over Iterable

可能重复:

据我所知,foreach循环是在Java5中添加的语法。所以

Iterable<O> iterable;
for(O o : iterable) {
    // Do something
}
(这实际上是对Iterable API的一种丑陋的滥用,因为它只能迭代一次!)

如果它是围绕
迭代器
而不是iterable设计的,那么可以做很多有趣的事情:

for(O o : iterable.iterator()) {} // Iterate over Iterable and Collections

for(O o : list.backwardsIterator()) {} // Or backwards

Iterator<O> iter;
for(O o : iter) {
    if (o.something()) { iter.remove(); }
    if (o.something()) { break; }
}
for(O : iter) { } // Do something with the remaining elements only.
for(O:iterable.iterator()){}//迭代iterable和集合
对于(O:list.backwardsIterator()){}//或向后
迭代器iter;
用于(O:iter){
如果(o.something()){iter.remove();}
如果(o.something()){break;}
}
对于(O:iter){}//只对剩余的元素进行处理。
有人知道为什么语言是这样设计的吗?如果一个类同时实现了
迭代器
Iterable
,则可以避免歧义?为了避免程序员错误,假设“for(O:iter)”将处理所有元素两次(并且忘记获取新的迭代器)?还是有其他原因


或者有什么我不知道的语言技巧吗?

Iterable接口就是为了这个目的而创建的(增强for循环),如中所述,尽管迭代器接口已经在使用中

关于JSR中讨论的新接口(注意包名称):

  • java.lang.Iterable
  • java.lang.ReadOnlyIterator
    (JSR中建议将其改装为
    java.util.Iterator
    ,但实际上并未完成)
…JSR说:

这些新接口用于防止该语言依赖于
java.util
,否则会产生这种依赖


所以我现在有一个合理的解释:

简短版本:因为语法也适用于没有迭代器的数组。

如果像我建议的那样,语法是围绕迭代器设计的,那么它将与数组不一致。让我给出三种变体:

A)由Java开发人员选择:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
while(iter.hasNext()) { Object o = iter.next(); }
现在数组和集合不一致;但是数组和ArrayList关系非常密切,它们的行为应该是相同的。现在,如果在任何时候,该语言被扩展以使数组实现
Iterable
,那么它就会变得不一致

C)允许所有三种情况:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
for(Object o : iter) { }
但这需要更改运行时环境,而不仅仅是编译器,并破坏向后兼容性。此外,上述混淆仍然存在

Iterator<Object> iter;
for(Object o : iter) { }
for(Object o : iter) { }
迭代器iter;
对于(对象o:iter){}
对于(对象o:iter){}
只在数据上迭代一次。

因为“for”循环会破坏迭代器。除非迭代器实现ListIterator子接口,否则无法重置迭代器(即移回开头)

一旦您将迭代器放入“for”循环,它将不再可用。我的猜测是,语言设计人员认为,这与编译器中的其他特殊情况(其中已有两种情况用于Iterable和Array)结合起来,将其转换为字节码(不能重用与Iterable相同的转换),足以成为一个贬损者而不去实现它

当您自己通过迭代器接口在代码中这样做时,至少可以明显看出发生了什么

随着lambdas的到来,他们可以让这一切变得轻松愉快:

Iterator<String> iterator = ...;
Collections.each ( iterator, (String s) => { System.out.println(s); } );

List<String> list = ...;
Collections.each ( list, (String s) => { System.out.println(s); } );
Iterator迭代器=。。。;
Collections.each(迭代器,(字符串s)=>{System.out.println(s);});
列表=。。。;
Collections.each(list,(String s)=>{System.out.println(s);});

在不破坏向后兼容性的情况下,仍然具有相对简单的语法。我怀疑他们是否会将“each”、“collect”和“map”这样的方法构建到不同的接口中,因为这会破坏向后兼容性,而且还有数组需要处理。

我认为答案的一部分可能隐藏在for-each循环是语法糖这一事实中。关键是你想让人们做的事情变得容易很多。还有(至少以我的经验来看)这个成语

Iterator iterator = iterable.iterator();
while( iterator.hasNext() ) {
  Element e = (Element)iterator.next() ;
}

在旧式代码中一直发生。而使用多个迭代器做一些奇特的事情却没有

或者。两者都是相近的重复项,但不完全相同。迭代器不应该是可迭代的,因为您只能迭代一次(没有“重新启动”)。我知道不能在迭代器上使用foreach(除非您使用我概述的适配器),但我试图理解为什么Java是这样设计的;我倾向于不同意。1.5文档中给出的答案简单地说明了设计师选择这种方式来处理最常见的用例。有时答案是“仅仅因为”。有时设计者有理由以这样或那样的方式设计语言。。。试图理解他们的推理有什么错(即使我无法改变事情)?谁说试图理解他们的推理有什么错?我所说的是,他们决定抓住低垂的果实,这是他们做的方式,不一定有太多的理解。谢谢你的指点。我现在大概知道了原因。显然,引入
java.lang.Iterable
而不是仅仅使用
java.util.Iterator
的基本原理是避免核心语言依赖于
java.util
)“使用迭代器语法,我们需要写…”为什么?因为否则我可以让一个类同时实现
Iterable
Iterator
,并造成很大的时间混乱。这与数组有什么关系?不管怎样,我都可以这样做,不需要参考数组——这正是我在回答中所说的那种复杂性(斜杠“guess”:-)。您希望数组的语法与集合的语法相同,集合是
Iterable
,而不是
it
Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
for(Object o : iter) { }
Object[] array;
for(Object o : array.iterator()) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }
Iterator<Object> iter;
for(Object o : iter) { }
for(Object o : iter) { }
Iterator<String> iterator = ...;
Collections.each ( iterator, (String s) => { System.out.println(s); } );

List<String> list = ...;
Collections.each ( list, (String s) => { System.out.println(s); } );
Iterator iterator = iterable.iterator();
while( iterator.hasNext() ) {
  Element e = (Element)iterator.next() ;
}