第46条:for-each循环优先于传统的for循环

看看这段代码有啥问题:

enum Suit { CLUB, DIAMOND, HEART, SPADE }
enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
NINE, TEN, JACK, QUEEN, KING }
...
Collection suits = Arrays.asList(Suit.values());
Collection ranks = Arrays.asList(Rank.values());
List deck = new ArrayList();
for (Iterator i = suits.iterator(); i.hasNext(); )
       for (Iterator j = ranks.iterator(); j.hasNext(); )
              deck.add(new Card(i.next(), j.next()));

如果你没有发现这个bug也不用沮丧,许多专家级的程序员也时不时的犯这种错误。问题出在调用了太多的外层集合(suits)迭代器上的next方法。本来它应该在外层循环里被调用,这样每个suit调用一次,然而,现在它在内层循环中被调用,变成了每个card调用一次。在你运行完suits,循环会抛出NoSuchElementException.

如果你很不幸,外层集合的长度是内层循环的倍数-或许因为它们是相同的集合-循环会正常中止,但结果却不是你想要的。例如,考虑下面有问题的代码,它企图打印所有可能的成对骰子数。

// Same bug, different symptom!
enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX }
...
Collection faces = Arrays.asList(Face.values());
for (Iterator i = faces.iterator(); i.hasNext(); )
       for (Iterator j = faces.iterator(); j.hasNext(); )
              System.out.println(i.next() + " " + j.next());

怎么解决这种问题:
方法1.

for (Iterator i = suits.iterator(); i.hasNext(); ) {
       Suit suit = i.next();
       for (Iterator 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 {
       // Returns an iterator over the elements in this iterable
       Iterator iterator();
}

实现这个接口并不困难。如果所写的类型代表一组元素,即便不让他实现Collection接口也应该让它实现Iterable接口。这会让你的用户可以通过for-each循环在你的类型上迭代,你的用户会永远感谢你。
总之,与传统的for循环相比,在简洁及防错方面,for-each循环有巨大的优势,而且没有性能损耗。只要可以使用就应该用之。不幸的是,有三种普遍情况无法使用for-each循环:
1、过滤-如果需要在集合上遍历且移去选定的元素,就要使用显式的迭代,并调用它的remove方法。
2、转换-如果需要在list或数组上遍历且要替换部分或所有的元素值,则需要list的迭代器或数组的索引去设置这些值。
3、平行迭代-如果需要并行的遍历多个集合,则需要显式的控制迭代器或索引变量,以便所有的迭代器或索引能协同推进(如上面的有问题的card和dice例子所示)。

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

你可能感兴趣的:(第46条:for-each循环优先于传统的for循环)