問題描述
可能重復:
為什么Java的Iterator不是Iterable?
給定for-each循環的慣用方式迭代器?
我們可以使用用于迭代Iterator類型對象的for-each循環?
據我所知,foreach 循環是 Java 5 中添加的語法糖.所以
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
}
基本上會產生與
Iterable<O> iterable;
for(Iterator<O> iter = iterable.iterator(); iter.hasNext(); /* NOOP */) {
O o = iter.next();
// Do something
}
但是,如果我一開始沒有可迭代對象,而只有一個迭代器(比如說,因為一個類提供了兩個不同的迭代器),我就不能使用語法糖 foreach 循環.顯然我仍然可以進行簡單的舊樣式迭代.但是,我實際上想做:
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
}
當然我可以做一個假的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;
}
}
(這實際上是對 Iterable API 的丑陋濫用,因為它只能迭代一次!)
(Which in fact is an ugly abuse of the Iterable API, as it can only be iterated once!)
如果它是圍繞 Iterator
而不是 iterable 設計的,可以做很多有趣的事情:
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.
有人知道為什么語言是這樣設計的嗎?如果一個類同時實現 Iterator
和 Iterable
,為了避免歧義?為了避免假定for(O o : iter)"的程序員錯誤;將處理所有元素兩次(并忘記獲取新的迭代器)?還是有其他原因?
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?
還是有一些我不知道的語言技巧?
Or is there some language trick I just do not know?
推薦答案
所以我現在有了一個比較合理的解釋:
So I have a somewhat reasonable explanation now:
短版:因為語法也適用于沒有迭代器的數組.
Short version: Because the syntax also applies to arrays, which don't have iterators.
如果語法是按照我的建議圍繞 Iterator
設計的,它將與數組不一致.讓我給出三個變體:
If the syntax were designed around Iterator
as I proposed, it would be inconsistent with arrays. Let me give three variants:
A) 由 Java 開發人員選擇:
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(); }
行為方式相同,并且在數組和集合之間高度一致.然而,迭代器必須使用經典的迭代風格(至少不會導致錯誤).
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) 允許數組和Iterators
:
Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }
現在數組和集合不一致;但是數組和 ArrayList 密切相關,應該表現相同.現在,如果在任何時候,該語言將被 擴展 以制作例如數組實現了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) 允許所有三個:
Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
for(Object o : iter) { }
現在,如果我們最終處于不清楚的情況下,當有人實現 both Iterable
和 Iterator
時(for 循環是否應該得到一個新的迭代器或迭代當前 - 在樹狀結構中很容易發生!?!).不幸的是,一個簡單的 tie-braker ala Iterable beats Iterator"是行不通的:它突然引入了運行時與編譯時間差異和泛型問題.
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.
現在突然間,我們需要注意是要迭代集合/可迭代對象還是數組,此時我們以大混亂為代價獲得了很少的好處.
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"的方式非常一致,它導致的編程錯誤非常少,并且允許將來可能將數組轉換為常規對象.
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.
有一個變體 D) 可能也可以正常工作:for-each 僅適用于迭代器.最好通過向原始數組添加 .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) { }
但這需要更改運行時環境,而不僅僅是編譯器,并且會破壞向后兼容性.另外,上面提到的混淆仍然存在,
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) { }
只對數據進行一次迭代.
Only iterates over the data once.
這篇關于為什么 Java 不允許在迭代器上使用 foreach(僅在可迭代對象上)?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!