JDK1.5中新的语言特征——For-Each 循环[转]

在先前的版本中,迭代一个集合的代码显得有点丑陋。


考虑下面的函数,它接受一个包含TimerTask 的集合,然后将那些 TimeTask 删去(concel)。

void cancelAll(Collection c) {
     for (Iterator i = c.iterator(); i.hasNext(); )
         i.next().cancel();
}
Iterator 简直可以叫混乱( clutter)。更糟的是,它还是产生错误的温床。 Iterator 变量在每个循环中出现三次:这就有两个机会出错。 For-each 句式除去了混乱和产生错误的温床。下面就是前面的例子用 for-each句式改写后的样子:
void cancelAll(Collection c) {
     for (TimerTask t : c)
         t.cancel();
}

冒号(:)读为"in."。上面的循环读作"for each TimerTask t in c." 如你所见,for-each 句式与泛型完美地结合了起来。它在除去残存的混乱的同时,保留了所有的类型安全性。因为你不用声明Iterator 变量,你不用为它提供一个泛型声明。(编译器在背后为你做了这些事,但你不需要对此有顾虑。)
下面是人们通常会犯的一个错误,当他们试图对两个集合进行嵌套的迭代的时候:
List suits = ...;
List ranks = ...;
List sortedDeck = new ArrayList();

// BROKEN - throws NoSuchElementException!
for (Iterator i = suits.iterator(); i.hasNext(); )
     for (Iterator j = ranks.iterator(); j.hasNext(); )
         sortedDeck.add(new Card(i.next(), j.next()));
你能找到臭虫吗?如果不能,也别介怀。很多编程老手都曾犯过这样的错误。问题就在于:在外部集合上(suits),next 方法被调用了太多次了,在内部循环中,内部集合和外部集合都调用了next,这是错的。想要改正这个错误,你不得不在外部循环中添加一个变量来保存该suit:
// Fixed, though a bit ugly
for (Iterator i = suits.iterator(); i.hasNext(); ) {
     Suit suit = (Suit) i.next();
     for (Iterator j = ranks.iterator(); j.hasNext(); )
         sortedDeck.add(new Card(suit, j.next()));
}
那么,这些与for-each 有什么关系呢?它是为嵌套的迭代订做的!看看下面的代码是多赏心悦目:
for (Suit suit : suits)
     for (Rank rank : ranks)
         sortedDeck.add(new Card(suit, rank));
For-each 句式也适用于数组,这种情况下它隐藏的不是iterator 而是下标变量。下面的函数返回int数组中所有值的和:
// Returns the sum of the elements of a
int sum(int[] a) {
     int result = 0;
     for (int i : a)
         result += i;
     return result;
}
那么,你应该在什么时候使用for-each 循环呢?任何时候。它真的美化了你的代码。不幸的是,你不能在任何地方使用它。比如说,考虑 expurgate 函数。为了删除当前元素,程序需要访问iterator。而 for-each 循环隐藏了iterator,所以你不能调用 remove 函数。因此,对于过滤(filtering)操作,for-each 循环无能为力。类似地,如果你想在遍历一个list或数组的时候替换元素,它也无能为力。最后,对于必须平行地迭代多个集合的循环,它也无能为力。这些缺点,设计者已熟知,他们已经经过深思熟虑,决定使用一个在大多数情况下可用的整洁而简单的句式。 

你可能感兴趣的:(jdk,list,iterator,语言,each,编译器)