7.1 Ditching Iterators
At its most basic, the for/in statement
gets rid of the need to use the
java.util.Iterator class. That class, useful in looping over collections
of objects, was rarely useful in and of itself. Instead, it made looping, and
accessing the objects in that loop, possible. As a means to an end,
though, Sun cut out the explicit usage of Iterator and streamlined the
basic for loop in the process. As a result, you too can ditch the usage of
Iterator.
7.1.1 How do I do that?
You certainly remember
the old (yup, it is indeed old now) for loop:
NOTEAll the unnamed samples in this chapter are in the class com.oreilly.
/** From ForInTester.java */
public void testForLoop(PrintStream out) throws IOException {
List list = getList( ); // initialize this list elsewhere
for (Iterator i = list.iterator( ); i.hasNext( ); ) {
Object listElement = i.next( );
out.println(listElement.toString( ));
// Do something else with this list object
}
}
tiger.ch07. ForInTester. Remember to compile using the "-source 1.5" switch
with "javac".This is a perfect example of Iterator simply being the means of getting
at objects in the list, rather than providing real value to the loop. for/in
allows this loop to be rewritten:
NOTEThis removal of Iterator has some consequencessee the later labs in
public void testForInLoop(PrintStream out) throws IOException {
List list = getList( ); // initialize this list elsewhere
for (Object listElement : list) {
out.println(listElement.toString( ));// Do something else with this list element
}
}
the chapter for details.Notice that the line Object listElement = i.next( ); from the first code
sample has disappeared. This is the basis of what for/in doesit
removes the Iterator from the process.
7.1.2 What just happened?
For those of you into specifications and language structure, the loop is
structured like this:
The Java specification defines the precise behavior of the for/in loop by
for (declaration : expression)
statement
translating it to the equivalent for loops shown below. In these loop
translations, the terms
declaration, expression
, and
statement
should
be replaced with the corresponding part of the for/in loop. The identifiers
beginning with # are synthetic variables that the compiler uses for
the translation. Their names are not legal Java identifiers, and you cannot
use them in the loop body.A for/in loop in which the compile-time type of the expression is
Iterable<E>
(discussed in "Avoiding Unnecessary Typecasts"), is translated
to this for loop:
Chapter 2.If
for ( Iterator<E> #i = (expression).iterator( ); #i.hasNext( ); ) {
declaration = #i.next( );
statement
}
expression
does not use generics
and its compile-time type is just an
unparameterized Iterable, then the loop is translated in the same way
except that the
<E>
is dropped:
If the compile-time type of
for ( Iterator #i = (expression).iterator( ); #i.hasNext( ); ) {
declaration = #i.next( );
statement
}
expression
is an array of type
T[], where
T
is
any primitive or reference type, then the loop is translated as follows:
Note that this code is designed to ensure that
{
T[] #a = expression;labels
for (int #i = 0; #i < #a.length; #i++) {
declaration = #a[ #i ] ;
statement
}
}
expression
is evaluated
only once. If the for/in loop is labeled with one or more labels, those
labels are translated as shown so that they appear after the evaluation of
expression
. This makes a labeled continue within the loop statement
work correctly.There are some further points about the syntax of the for/in loop that
you should be aware of:
expression
must be either an array or an object that implements the
java.lang.Iterable interface. The compiler must be able to ensure
this at compile-timeso you can't use a List cast to Object, for
example, and expect things to behave.The type of the array
or Iterable elements must be assignmentcompatible
with the type of the variable declared in the
declaration
. If the assignment won't work, you're going to get
errors.The
declaration
usually consists of
just a type and a variable name,
but it may include a final modifier and any appropriate annotations
(see Chapter 6 on Annotations). Using final prevents the loop variable
from taking on any value other than the array or collection element
the loop assigns. It also emphasizes the fact that the array or
collection cannot be altered through the loop variable.The loop variable of the for/in loop must be declared as part of the
loop, with both a type and a variable name. You cannot use a variable
declared outside the loop as you can with the for loop.
NOTEUsing the "final" modifier is a good way to ensure bulletproof code,
unless you really need to modify the loop variable.
7.1.3 What about...
...just using a regular for loop? You're welcome to it. for/in really doesn't
add any functionalityit's ultimately about convenience. And you'll see
several instances in this chapter where this convenience comes with a
functionality loss, rather than gain. So, if you're only in it to get something
done, for/in doesn't really offer you much, other than the ability to
keep up with the number of times you need to iterate over a collection.
On the other hand, if your goal in life is to type as little as possible, or if
you just want to be the cool guy who uses new and odd-looking structures,
for/in is perfect.