跟我学(Effective Java 2)第46条:for-each循环优先于传统的for循环

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

for-each循环通过完全隐藏迭代器或者索引变量,避免混乱和出错的可能,适用于集合和数组和任何实现Iterable接口的对象。

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()));

如果你没有发现这个bug也不用难过,许多专家级的程序员也偶尔会犯这种错误。问题在于,在迭代器上对外层集合(suits)调用了太多次next的方法。它应该从外层循环被调用,以便每个suit调用一次,但是它却是在内层循环中被调用,变成了每个card调用一次。在你运行完suits,循环会抛出NoSuchElementException。

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

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());

期望打印预计的36中组合,结果却是6个重复的词。

修正方法:

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()));
}

使用嵌套for-each循环更简洁:

for (Suit suit : suits)
       for (Rank rank : ranks)
              deck.add(new Card(suit, rank));

or-each不仅可在集合和数组上迭代,而且还可在任何实现了Iterable接口的对象上迭代。接口Iterablel有一个简单的方法,随for-each一起加入平台,接口如下:

public interface Iterable<E> {
       Iterator<E> iterator();
}

实现Iterable接口并不困难。如果所写的类型代表一组元素,即便不让他实现Collection接口也应该让它实现Iterable接口。这会让你的用户可以通过for-each循环在你的类型上迭代,你的用户会永远感谢你。

总之,使用嵌套for-each循环更简洁,代码优雅,性能略胜于普通for循环,因为它对数组索引的边界值只计算一次。

无法使用for-each循环的情况:

1.过滤 ,需要遍历集合并删除选定的元素,需要显式的迭代器,以便调用它的remove方法。

2.转换 ,需要遍历列表或者数组,并取代它部分或者全部元素值,需要列表迭代器或者数组索引,以便设定元素的值。

3.平行迭代 ,并行地遍历多个集合,需要显式地控制迭代器或者索引变量,以便所有迭代器和索引变量都可以得到同步前移(像上述第一个代码 块那样)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值