看看這段代碼有啥問題:
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ā)現這個bug也不用沮喪非驮,許多專家級的程序員也時不時的犯這種錯誤荆陆。問題出在調用了太多的外層集合(suits)迭代器上的next方法剑辫。本來它應該在外層循環(huán)里被調用礼殊,這樣每個suit調用一次,然而依疼,現在它在內層循環(huán)中被調用,變成了每個card調用一次闸衫。在你運行完suits涛贯,循環(huán)會拋出NoSuchElementException.
如果你很不幸,外層集合的長度是內層循環(huán)的倍數-或許因為它們是相同的集合-循環(huán)會正常中止蔚出,但結果卻不是你想要的弟翘。例如,考慮下面有問題的代碼骄酗,它企圖打印所有可能的成對骰子數稀余。
// 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不僅可在集合和數組上迭代,而且還可在任何實現了Iterable接口的對象上迭代趋翻。接口Iterablel有一個簡單的方法睛琳,隨for-each一起加入平臺,接口如下:
public interface Iterable<E> {
// Returns an iterator over the elements in this iterable
Iterator<E> iterator();
}
實現這個接口并不困難。如果所寫的類型代表一組元素师骗,即便不讓他實現Collection接口也應該讓它實現Iterable接口历等。這會讓你的用戶可以通過for-each循環(huán)在你的類型上迭代,你的用戶會永遠感謝你辟癌。
總之寒屯,與傳統(tǒng)的for循環(huán)相比,在簡潔及防錯方面黍少,for-each循環(huán)有巨大的優(yōu)勢寡夹,而且沒有性能損耗。只要可以使用就應該用之厂置。不幸的是菩掏,有三種普遍情況無法使用for-each循環(huán):
1、過濾-如果需要在集合上遍歷且移去選定的元素昵济,就要使用顯式的迭代智绸,并調用它的remove方法。
2砸紊、轉換-如果需要在list或數組上遍歷且要替換部分或所有的元素值传于,則需要list的迭代器或數組的索引去設置這些值。
3醉顽、平行迭代-如果需要并行的遍歷多個集合沼溜,則需要顯式的控制迭代器或索引變量,以便所有的迭代器或索引能協(xié)同推進(如上面的有問題的card和dice例子所示)游添。