Java:为什么不能迭代迭代器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2598219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: why can't iterate over an iterator?
提问by noamtm
I read Why is Java's Iterator not an Iterable?and Why aren't Enumerations Iterable?, but I still don't understand why this:
我读了为什么 Java 的迭代器不是可迭代的?而为什么不枚举可迭代?,但我仍然不明白为什么会这样:
void foo(Iterator<X> it) {
for (X x : it) {
bar(x);
baz(x);
}
}
was not made possible. In other words, unless I'm missing something, the above could have been nice and valid syntactic sugar for:
是不可能的。换句话说,除非我遗漏了一些东西,否则上面的内容可能是很好且有效的语法糖:
void foo(Iterator<X> it) {
for (X x; it.hasNext();) {
x = it.next();
bar(x);
baz(x);
}
}
采纳答案by gustafc
but I still don't understand why this [...]was not made possible.
但我仍然不明白为什么这[...]没有成为可能。
I can see several reasons:
我可以看到几个原因:
Iterator
s are not reusable, so a for/each would consume the iterator - not incorrect behavior, perhaps, but unintuitive to those who don't know how the for/each is desugared.Iterator
s don't appear "naked" in code all that often so it would be complicating the JLS with little gain (the for/each construct is bad enough as it is, working on bothIterable
s and arrays).- There's an easy workaround. It may seem a little wasteful to allocate a new object just for this, but allocation is cheap as it is and escape analysis would rid you even of that small cost in most cases. (Why they didn't include this workaround in an
Iterables
utility class, analogous toCollections
andArrays
, is beyond me, though.) - (Probably not true - see the comments.)
I seem to recall that the JLS can only reference things injava.lang
[citation needed], so they'd have to create anIterator
interface injava.lang
whichjava.util.Iterator
extends without adding anything to. Now we have twofunctionally equivalent iterator interfaces. 50% of the new code using naked iterators will choose thejava.lang
version, the rest use the one injava.util
. Chaos ensues, compatibility problems abound, etc.
Iterator
s 不可重用,因此 for/each 会消耗迭代器——这可能不是错误的行为,但对于那些不知道 for/each 如何脱糖的人来说是不直观的。Iterator
s 不会经常在代码中出现“裸体”,因此它会使 JLS 变得复杂,但收益很小(for/each 构造已经足够糟糕,同时适用于Iterable
s 和数组)。- 有一个简单的解决方法。仅仅为此分配一个新对象似乎有点浪费,但分配很便宜,而且在大多数情况下,逃逸分析甚至可以让您免去这么小的成本。(不过,为什么他们没有在
Iterables
类似于Collections
and的实用程序类中包含此解决方法,这Arrays
超出了我的理解。) - (可能不是真的 - 请参阅评论。)
我似乎记得 JLS 只能引用java.lang
[需要引用] 中的内容,因此他们必须创建一个Iterator
接口,在java.lang
其中java.util.Iterator
扩展而不添加任何内容。现在我们有两个功能等效的迭代器接口。50% 使用裸迭代器的新代码会选择java.lang
版本,其余使用java.util
. 随之而来的混乱,兼容性问题比比皆是,等等。
I think points 1-3 are very much in line with how the Java language design philosophy seems to go: Don't surprise newcomers, don't complicate the spec if it doesn't have a clear gain that overshadows the costs, and don't do with a language feature what can be done with a library.
我认为第 1-3 点非常符合 Java 语言设计理念的方式:不要让新手感到惊讶,如果规范没有明显的收益超过成本,请不要使规范复杂化,并且不要不能用语言功能做图书馆可以做的事情。
The same arguments would explain why java.util.Enumeration
isn't Iterable
, too.
同样的论点也可以解释为什么java.util.Enumeration
不是Iterable
。
回答by Michael Aaron Safyan
Most likely the reason for this is because iterators are not reusable; you need to get a fresh Iterator from the Iterable collection each time you want to iterate over the elements. However, as a quick fix:
最有可能的原因是迭代器不可重用;每次要遍历元素时,都需要从 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
}
// ...
}
//....
That said, the best thing to do is simply pass around the Iterable<T>
interface instead of Iterator<T>
也就是说,最好的办法就是简单地传递Iterable<T>
接口而不是Iterator<T>
回答by jjnguy
The for(Type t : iterable)
syntax is only valid for classes that implement Iterable<Type>
.
该for(Type t : iterable)
语法仅对实现Iterable<Type>
.
An iterator does not implement iterable.
迭代器不实现可迭代。
You can iterate over things like Collection<T>
, List<T>
, or Set<T>
because they implement Iterable.
您可以迭代诸如Collection<T>
, 之类的东西List<T>
,或者Set<T>
因为它们实现了 Iterable。
The following code is equivalent:
下面的代码是等价的:
for (Type t: list) {
// do something with t
}
and
和
Iterator<Type> iter = list.iterator();
while (iter.hasNext()) {
t = iter.next();
// do something with t
}
The reason this was not made possible, is because the for-each syntax was added to the language to abstract out the Iterator
. Making the for-each loop work with iterators would not accomplish what the for-each loop was created for.
之所以无法做到这一点,是因为在语言中添加了 for-each 语法以抽象出Iterator
. 使 for-each 循环与迭代器一起工作不会完成 for-each 循环的创建目的。
回答by Itay Maman
Iterators are not meant be reused (i.e.: used in more than one iteration loop). In particular, Iterator.hasNext()
guarantees that you can safely call Iterator.next()
and indeed get the next value from the underlying collection.
迭代器并不意味着可以重用(即:在多个迭代循环中使用)。特别是,Iterator.hasNext()
保证您可以安全地调用Iterator.next()
并确实从基础集合中获取下一个值。
When the same iterator is used in two concurrently running iterations (let's assume a multi-threading scenario), this promise can no longer be kept:
当在两个并发运行的迭代中使用同一个迭代器时(让我们假设一个多线程场景),这个承诺就不能再保持了:
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
}
Such scenarios completely break the protocol offered by Iterator. Actually, they can occur even in a single threaded program: an iteration loop calls another method which uses the same iterator to perform its own iteration. When this method returns, the caller is issuing an Iterator.next()
call which, again, fails.
这样的场景完全破坏了 Iterator 提供的协议。实际上,它们甚至可以在单线程程序中发生:迭代循环调用另一个使用相同迭代器执行自己的迭代的方法。当此方法返回时,调用者发出的Iterator.next()
调用再次失败。
回答by polygenelubricants
Because the for-each is designed to read as something like:
因为 for-each 旨在读取如下内容:
for each element of [some collection of elements]
An Iterator
is not [some collection of elements]
. An array and an Iterable
is.
一个Iterator
不是[some collection of elements]
。一个数组和一个Iterable
是。
回答by Vadzim
Actually, you can.
事实上,你可以。
There is very short workaround available on java 8:
java 8 上有很短的解决方法:
for (X item : (Iterable<X>) () -> iterator)
See How to iterate with foreach loop over java 8 streamfor the detailed explanation of the trick.
有关该技巧的详细说明,请参阅如何在 java 8 流上使用 foreach 循环进行迭代。
And some explanations why this was not natively supported can be found in related question:
在相关问题中可以找到一些解释为什么这不被本地支持: