問(wèn)題描述
可能重復(fù):
為什么Java的Iterator不是Iterable?
給定for-each循環(huán)的慣用方式迭代器?
我們可以使用用于迭代Iterator類(lèi)型對(duì)象的for-each循環(huán)?
據(jù)我所知,foreach 循環(huán)是 Java 5 中添加的語(yǔ)法糖.所以
The foreach loop are as far as I know syntax sugar added in Java 5. So
Iterable<O> iterable;
for(O o : iterable) {
// Do something
}
基本上會(huì)產(chǎn)生與
Iterable<O> iterable;
for(Iterator<O> iter = iterable.iterator(); iter.hasNext(); /* NOOP */) {
O o = iter.next();
// Do something
}
但是,如果我一開(kāi)始沒(méi)有可迭代對(duì)象,而只有一個(gè)迭代器(比如說(shuō),因?yàn)橐粋€(gè)類(lèi)提供了兩個(gè)不同的迭代器),我就不能使用語(yǔ)法糖 foreach 循環(huán).顯然我仍然可以進(jìn)行簡(jiǎn)單的舊樣式迭代.但是,我實(shí)際上想做:
However, if I do not have an iterable in the first place, but only an iterator (say, because a class offers two different iterators), I cannot use the syntax sugar foreach loop. Obviously I can still do the plain old style iteration. However, I'd actually like to do:
Iterator<O> iter;
for(O o : iter /* Iterator<O>, not Iterable<O>! */) {
// Do something
}
當(dāng)然我可以做一個(gè)假的Iterable
:
And of course I can do a fake Iterable
:
class Adapter<O> implements Iterable<O> {
Iterator<O> iter;
public Adapter(Iterator<O> iter) {
this.iter = iter;
}
@Override
public Iterator<O> iterator() {
return iter;
}
}
(這實(shí)際上是對(duì) Iterable API 的丑陋濫用,因?yàn)樗荒艿淮危?
(Which in fact is an ugly abuse of the Iterable API, as it can only be iterated once!)
如果它是圍繞 Iterator
而不是 iterable 設(shè)計(jì)的,可以做很多有趣的事情:
If it were designed around Iterator
instead of iterable, one could do a number of interesting things:
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.
有人知道為什么語(yǔ)言是這樣設(shè)計(jì)的嗎?如果一個(gè)類(lèi)同時(shí)實(shí)現(xiàn) Iterator
和 Iterable
,為了避免歧義?為了避免假定for(O o : iter)"的程序員錯(cuò)誤;將處理所有元素兩次(并忘記獲取新的迭代器)?還是有其他原因?
Does anyone know why the language was designed this way? To avoid ambiguity if a class would implement both Iterator
and Iterable
? To avoid programmer errors that assume that "for(O o : iter)" will process all elements twice (and forget to get a fresh iterator)? Or is there some other reason for this?
還是有一些我不知道的語(yǔ)言技巧?
Or is there some language trick I just do not know?
推薦答案
所以我現(xiàn)在有了一個(gè)比較合理的解釋:
So I have a somewhat reasonable explanation now:
短版:因?yàn)檎Z(yǔ)法也適用于沒(méi)有迭代器的數(shù)組.
Short version: Because the syntax also applies to arrays, which don't have iterators.
如果語(yǔ)法是按照我的建議圍繞 Iterator
設(shè)計(jì)的,它將與數(shù)組不一致.讓我給出三個(gè)變體:
If the syntax were designed around Iterator
as I proposed, it would be inconsistent with arrays. Let me give three variants:
A) 由 Java 開(kāi)發(fā)人員選擇:
A) as chosen by the Java developers:
Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
while(iter.hasNext()) { Object o = iter.next(); }
行為方式相同,并且在數(shù)組和集合之間高度一致.然而,迭代器必須使用經(jīng)典的迭代風(fēng)格(至少不會(huì)導(dǎo)致錯(cuò)誤).
The behaves the same way and is highly consistent across arrays and collections. Iterators however have to use the classic iteration style (which at least is not likely to cause errors).
B) 允許數(shù)組和Iterators
:
Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }
現(xiàn)在數(shù)組和集合不一致;但是數(shù)組和 ArrayList 密切相關(guān),應(yīng)該表現(xiàn)相同.現(xiàn)在,如果在任何時(shí)候,該語(yǔ)言將被 擴(kuò)展 以制作例如數(shù)組實(shí)現(xiàn)了Iterable
,就變得不一致了.
Now arrays and collections are inconsistent; but arrays and ArrayList are very closely related and should behave the same way. Now if at any point, the language is extended to make e.g. arrays implement Iterable
, it becomes inconsistent.
C) 允許所有三個(gè):
Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
for(Object o : iter) { }
現(xiàn)在,如果我們最終處于不清楚的情況下,當(dāng)有人實(shí)現(xiàn) both Iterable
和 Iterator
時(shí)(for 循環(huán)是否應(yīng)該得到一個(gè)新的迭代器或迭代當(dāng)前 - 在樹(shù)狀結(jié)構(gòu)中很容易發(fā)生!?!).不幸的是,一個(gè)簡(jiǎn)單的 tie-braker ala Iterable beats Iterator"是行不通的:它突然引入了運(yùn)行時(shí)與編譯時(shí)間差異和泛型問(wèn)題.
Now if we end up in unclear situations when either someone implements both Iterable
and Iterator
(is the for loop supposed to get a new iterator or iterate over the current - happens easily in tree-like structures!?!). A simple tie-braker ala "Iterable beats Iterator" unfortunately won't do: it suddenly introduces runtime vs. compile time difference and generics issues.
現(xiàn)在突然間,我們需要注意是要迭代集合/可迭代對(duì)象還是數(shù)組,此時(shí)我們以大混亂為代價(jià)獲得了很少的好處.
Now suddenly, we need to pay attention to whether we want to iterate over collections/iterables or arrays, at which point we have gained very little benefits at the cost of a big confusion.
Java (A) 中for each"的方式非常一致,它導(dǎo)致的編程錯(cuò)誤非常少,并且允許將來(lái)可能將數(shù)組轉(zhuǎn)換為常規(guī)對(duì)象.
The way "for each" is in Java (A) is very consistent, it causes very little programming errors, and it allows for the possible future change of turning arrays into regular objects.
有一個(gè)變體 D) 可能也可以正常工作:for-each 僅適用于迭代器.最好通過(guò)向原始數(shù)組添加 .iterator()
方法:
There is a variant D) that would probably also work okay:
for-each for Iterators only. Preferrably by adding a .iterator()
method to primitive arrays:
Object[] array;
for(Object o : array.iterator()) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }
但這需要更改運(yùn)行時(shí)環(huán)境,而不僅僅是編譯器,并且會(huì)破壞向后兼容性.另外,上面提到的混淆仍然存在,
But this requires changes to the runtime environment, not just the compiler, and breaks backwards compatibility. Plus, the mentioned confusion is still present that
Iterator<Object> iter;
for(Object o : iter) { }
for(Object o : iter) { }
只對(duì)數(shù)據(jù)進(jìn)行一次迭代.
Only iterates over the data once.
這篇關(guān)于為什么 Java 不允許在迭代器上使用 foreach(僅在可迭代對(duì)象上)?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!