第46條:for-each循環(huán)優(yōu)先于傳統(tǒng)的for循環(huán)

看看這段代碼有啥問題:

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例子所示)。

http://www.cnblogs.com/aoguren/p/4771589.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容