使用for-each的可以是一个数组,或者是实现Iterable<T>这个接口的对象(Collection<E>继承了这个接口,所有集合类都可以使用for-each)。
既然for循环能遍历一个数组或者集合,那么为什么还会有一个for-each做遍历呢?下面(参考了jdk1.8api)举例说明:
for循环遍历每一个TimerTask类型的元素,然后调用其cancel方法。
void cancelAll(Collection<TimerTask> c) { for (Iterator<TimerTask> i = c.iterator(); i.hasNext(); ) i.next().cancel(); }
你能从上面的代码发现有什么问题吗?如上确实能实现遍历操作集合元素的功能,但是迭代器变量在每个循环中出现三次,for-each构造摆脱了这样的问题。
void cancelAll(Collection<TimerTask> c) {
for (TimerTask t : c)
t.cancel();
}
冒号(:)读作“in”,上面的循环读作“对于c中的每个TimerTask t”。正如您所看到的,for-each构造
与泛型完美地结合在一起。它保留了所有类型的安全性。因为您不必声明迭代器,所以不必为其提供通用声明。
(编译器会在背后为你做这件事,但你不必关心它。)
对两个集合进行嵌套迭代时犯的常见错误:
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()));问题是“外部”集合(套装)上被调用了太多次。它在外部和内部集合的内部循环中被调用,这是错误的。
为了解决这个问题,在外循环的范围内添加一个变量来保存这个套装:
// 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构造也适用于数组,它隐藏了索引变量而不是迭代器。以下方法返回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方法。该程序需要访问迭代器才能删除当前元素。for-each循环隐藏了迭代器,所以你不能调用remove。因此,for-each循环不能用于遍历时有删除操作。同样,它不适用于需要在遍历列表或数组时替换元素的循环。最后,它不能用于必须并行迭代多个集合的循环。