对多个集合嵌套迭代,for-each比for优势更明显.
enum Suit { CLUB,DIAMOND,HEART,SPADE }
enum Rank { ACE, DEUCE, THREE, FORE, FIVE, SIX,SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING}
class Card {
publicSuit suit;
publicRank rank;
publicCard(Suit suit, Rank rank) {
this.suit= suit;
this.rank= rank;
}
public static void main(String[] args) {
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(newCard(i.next(), j.next()));
}
}
//Exceptionin thread "main" java.util.NoSuchElementException
}
}
看不出问题很正常的,因为很多专家级程序员依旧看不出这样的错误.问题在于,在迭代器对外部的集合suits调用太多次next方法.它应该在外部循环中进行,以便每种花色只调用1次,但是却从内部循环中调用多次,当然用完所有花色后,出现java.util.NoSuchElementException.
比出现异常更糟糕的情况,外部集合大小是内部集合大小的若干倍,可能因为它们是相同的集合,循环就会正常终止,但不会完成你想要的工作.下面代码考虑不周,打印一对骰子的所有可能滚法.
enum Face {ONE, TWO, THREE, FORE, 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.err.println(i.next()+ " "+ j.next());
}
}
与预期的目标36种不符合,只是打印6种情况.结果如下:
ONE ONE
TWO TWO
THREE THREE
FORE FORE
FIVE FIVE
SIX SIX
//具体为何,如果不知道,请断点调试.一目了然.
如何解决上面的两个问题呢?必须在外部循环的作用域中添加变量保存外部元素.
for (Iterator<Suit> i =suits.iterator(); i.hasNext();) {
Suit suit = (i.next();
for(Iterator<Rank> j = ranks.iterator(); j.hasNext();) {
deck.add(newCard(suit, j.next()));
}
}
如果使用嵌套for-each循环,此问题彻底消失,产生的代码如你所愿那样简洁.
for (Suit s: suits)
for(Rankrank:ranks)
deck.add(newCard(suit,rank))