我看过Why is Java's Iterator not an Iterable?和Why aren't Enumerations Iterable?,但我仍然不明白为什么会这样:
void foo(Iterator<X> it) {
for (X x : it) {
bar(x);
baz(x);
}
}
无法实现。换句话说,除非我遗漏了某些内容,否则以上内容可能是一个很好且有效的语法糖:
void foo(Iterator<X> it) {
for (X x; it.hasNext();) {
x = it.next();
bar(x);
baz(x);
}
}
答案 0 :(得分: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
}
// ...
}
//....
那就是说,最好的办法就是绕过Iterable<T>
界面,而不是Iterator<T>
答案 1 :(得分:9)
但我仍然不明白为什么 [...] 无法实现。
我可以看到几个原因:
Iterator
s不可重复使用,因此for / each会消耗迭代器 - 也许不是不正确的行为,但对那些不知道for / each如何被淘汰的人来说是不直观的。Iterator
s在代码中看起来并不是“赤裸裸”,因此它会使JLS变得很复杂,而且收益很小(for / each结构很糟糕,同时处理{{1} s和数组)。Iterable
实用程序类中包含此变通方法,类似于Iterables
和Collections
,但是我已经超出了我的范围。)Arrays
[citation needed] 中的内容,所以他们有在java.lang
中创建Iterator
接口java.lang
扩展而不添加任何内容。现在我们有两个功能相当的迭代器接口。使用裸迭代器的新代码的50%将选择java.util.Iterator
版本,其余使用java.lang
中的版本。随之而来的是混乱,兼容性问题比比皆是等等。我认为第1-3点与Java语言设计理念似乎非常一致:不要让新手感到惊讶,如果没有明显的收益来掩盖成本,请不要使规范复杂化,并且不使用语言功能可以使用库来完成。
同样的论点也可以解释为什么java.util
也不是java.util.Enumeration
。
答案 2 :(得分:6)
for(Type t : iterable)
语法仅对实现Iterable<Type>
的类有效。
迭代器不实现可迭代。
您可以迭代Collection<T>
,List<T>
或Set<T>
之类的内容,因为它们实现了Iterable。
以下代码是等效的:
for (Type t: list) {
// do something with t
}
和
Iterator<Type> iter = list.iterator();
while (iter.hasNext()) {
t = iter.next();
// do something with t
}
这是不可能的原因,是因为for-each语法被添加到语言中以抽象出Iterator
。使for-each循环与迭代器一起工作将无法实现for-each循环的创建。
答案 3 :(得分:4)
实际上,你可以。
java 8上有很短的解决方法:
for (X item : (Iterable<X>) () -> iterator)
有关技巧的详细说明,请参阅How to iterate with foreach loop over java 8 stream。
可以在相关问题中找到一些解释为什么这不是本机支持的:
答案 4 :(得分:2)
迭代器不应该被重用(即:在多个迭代循环中使用)。特别是,Iterator.hasNext()
保证您可以安全地调用Iterator.next()
并确实从底层集合中获取下一个值。
当在两个并发运行的迭代中使用相同的迭代器时(让我们假设一个多线程场景),不再保留这个承诺:
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提供的协议。实际上,它们甚至可以在单线程程序中出现:迭代循环调用另一个使用相同迭代器执行自己的迭代的方法。当此方法返回时,调用者正在发出Iterator.next()
调用,该调用再次失败。
答案 5 :(得分:0)
因为for-each被设计成如下所示:
for each element of [some collection of elements]
Iterator
不是[some collection of elements]
。数组和Iterable
是。