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.
You certainly remember the old (yup, it is indeed old now) for loop:
/** 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 } }
NOTE
All the unnamed samples in this chapter are in the class com.oreilly. 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:
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 } }
NOTE
This removal of Iterator has some consequencessee the later labs in 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.
For those of you into specifications and language structure, the loop is structured like this:
for (declaration : expression) statement
The Java specification defines the precise behavior of the for/in loop by 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:
for ( Iterator<E> #i = (expression).iterator( ); #i.hasNext( ); ) { declaration = #i.next( ); statement }
If 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:
for ( Iterator #i = (expression).iterator( ); #i.hasNext( ); ) { declaration = #i.next( ); statement }
If the compile-time type of expression is an array of type T[], where T is any primitive or reference type, then the loop is translated as follows:
{ T[] #a = expression;labels for (int #i = 0; #i < #a.length; #i++) { declaration = #a[ #i ] ; statement } }
Note that this code is designed to ensure that 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.
NOTE
Using the "final" modifier is a good way to ensure bulletproof code, unless you really need to modify the loop variable.
...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.