Iterating over a collection is uglier than it needs to be. Consider the following method, which takes a collection of timer tasks and cancels them:
(遍历一个集合的代码总是繁琐不堪,下面的方法展示了如何从集合里取出timer task并且取消)
void cancelAll(Collection<TimerTask> c) {
for (Iterator<TimerTask> i = c.iterator(); i.hasNext(); )
i.next().cancel();
}
The iterator is just clutter. Furthermore, it is an opportunity for error. The iterator variable occurs three times in each loop: that is two chances to get it wrong. The for-each construct gets rid of the clutter and the opportunity for error. Here is how the example looks with the for-each construct:
When you see the colon (:) read it as “in.” The loop above reads as “for each TimerTask t in c.” As you can see, the for-each construct combines beautifully with generics. It preserves all of the type safety, while removing the remaining clutter. Because you don't have to declare the iterator, you don't have to provide a generic declaration for it. (The compiler does this for you behind your back, but you need not concern yourself with it.)
(冒号(:)读作“在”。上面的循环读作“for each TimerTask t in c.”大家可能发现到for-each和泛型的完美结合。这样即可以保证类型安全又做到了保持代码简洁。因为你不必定义个迭代变量,不用定义一个泛型的迭代变量。注:实际上编译器完成这个动作,不用你亲自为之。)
Here is a common mistake people make when they are trying to do nested iteration over two collections:
(下面是大家在嵌套迭代两个结合时容易犯的错误:)
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()));
Can you spot the bug? Don't feel bad if you can't. Many expert programmers have made this mistake at one time or another. The problem is that the next method is being called too many times on the “outer” collection (suits). It is being called in the inner loop for both the outer and inner collections, which is wrong. In order to fix it, you have to add a variable in the scope of the outer loop to hold the suit:
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()));
}
So what does all this have to do with the for-each construct? It is tailor-made for nested iteration! Feast your eyes:
(这些和for-each有什么联系吗?for-each可以说是为嵌套迭代量身定做的!大饱眼福吧:)
for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));
The for-each construct is also applicable to arrays, where it hides the index variable rather than the iterator. The following method returns the sum of the values in an int array:
So when should you use the for-each loop? Any time you can. It really beautifies your code. Unfortunately, you cannot use it everywhere. Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel. These shortcomings were known by the designers, who made a conscious decision to go with a clean, simple construct that would cover the great majority of cases.