Spec-Zone .ru
спецификации, руководства, описания, API
|
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:
void cancelAll(Collection<TimerTask> c) { for (TimerTask t : c) t.cancel(); }
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.)
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:
// 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())); }
So what does all this have to do with the for-each construct? It is tailor-made for nested iteration! Feast your eyes:
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:
// Returns the sum of the elements of a int sum(int[] a) { int result = 0; for (int i : a) result += i; return result; }
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.
Java Technology |
Copyright © 1993, 2010, Oracle and/or its affiliates. All rights reserved. |