看看這段代碼有啥問題:
enum Suit { CLUB, DIAMOND, HEART, SPADE }
enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
NINE, TEN, JACK, QUEEN, KING }
...
Collection<Suit> suits = Arrays.asList(Suit.values());
Collection<Rank> ranks = Arrays.asList(Rank.values());
List<Card> deck = new ArrayList<Card>();
for (Iterator<Suit> i = suits.iterator(); i.hasNext(); )
for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
deck.add(new Card(i.next(), j.next()));
如果你沒有發(fā)現(xiàn)這個bug也不用沮喪,許多專家級的程序員也時不時的犯這種錯誤。問題出在調(diào)用了太多的外層集合(suits)迭代器上的next方法。本來它應(yīng)該在外層循環(huán)里被調(diào)用,這樣每個suit調(diào)用一次,然而,現(xiàn)在它在內(nèi)層循環(huán)中被調(diào)用,變成了每個card調(diào)用一次。在你運(yùn)行完suits,循環(huán)會拋出NoSuchElementException.
如果你很不幸,外層集合的長度是內(nèi)層循環(huán)的倍數(shù)-或許因為它們是相同的集合-循環(huán)會正常中止,但結(jié)果卻不是你想要的。例如,考慮下面有問題的代碼,它企圖打印所有可能的成對骰子數(shù)。
// Same bug, different symptom!
enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX }
...
Collection<Face> faces = Arrays.asList(Face.values());
for (Iterator<Face> i = faces.iterator(); i.hasNext(); )
for (Iterator<Face> j = faces.iterator(); j.hasNext(); )
System.out.println(i.next() + " " + j.next());
怎么解決這種問題:
方法1.
for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) {
Suit suit = i.next();
for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); )
deck.add(new Card(suit, j.next()));
}
方法2.
for (Suit suit : suits)
for (Rank rank : ranks)
deck.add(new Card(suit, rank));
for-each不僅可在集合和數(shù)組上迭代,而且還可在任何實現(xiàn)了Iterable接口的對象上迭代。接口Iterablel有一個簡單的方法,隨for-each一起加入平臺,接口如下:
public interface Iterable<E> {
// Returns an iterator over the elements in this iterable
Iterator<E> iterator();
}
實現(xiàn)這個接口并不困難。如果所寫的類型代表一組元素,即便不讓他實現(xiàn)Collection接口也應(yīng)該讓它實現(xiàn)Iterable接口。這會讓你的用戶可以通過for-each循環(huán)在你的類型上迭代,你的用戶會永遠(yuǎn)感謝你。
總之,與傳統(tǒng)的for循環(huán)相比,在簡潔及防錯方面,for-each循環(huán)有巨大的優(yōu)勢,而且沒有性能損耗。只要可以使用就應(yīng)該用之。不幸的是,有三種普遍情況無法使用for-each循環(huán):
1、過濾-如果需要在集合上遍歷且移去選定的元素,就要使用顯式的迭代,并調(diào)用它的remove方法。
2、轉(zhuǎn)換-如果需要在list或數(shù)組上遍歷且要替換部分或所有的元素值,則需要list的迭代器或數(shù)組的索引去設(shè)置這些值。
3、平行迭代-如果需要并行的遍歷多個集合,則需要顯式的控制迭代器或索引變量,以便所有的迭代器或索引能協(xié)同推進(jìn)(如上面的有問題的card和dice例子所示)。