Java 1.5's hidden features

This article was originally published in VSJ, which is now part of Developer Fusion.
One of the coolest things about Java 1.5 is that it offers so many new language features. When Java 1.3 and 1.4 were released, they had some new goodies, but most of the changes were either implementation issues (like all the Collection class restructuring), or things you didn’t use everyday (like proxies). Java 1.5 is very different, though – you get to write new, funky-looking code, and that’s about as good as it gets for hard-core developers.

This article examines one of these new language features, the for/in loop. This name is a bit deceiving, as the loop never uses the “in” keyword; as a result, it’s often called enhanced for, and even sometimes foreach . No matter what you call it, though, it’s mostly a convenience function – it doesn’t make Java do anything particularly new, but it does save some keystrokes.

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 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
		//cthis list object
	}
}
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
	}
}
Notice that the line Object listElement = i.next( ); from the first code sample has disappeared. This is the basis of what for/in does – it 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 behaviour 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” later), is translated to this for loop using generics:

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 labelled with one or more labels, those labels are translated as shown so that they appear after the evaluation of expression. This makes a labelled 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-time – so 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 assignment-compatible 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. 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.
  • Using the “final” modifier is a good way to ensure bulletproof code, unless you really need to modify the loop variable.

    What about just using a regular for loop? You’re welcome to it. for/in really doesn’t add any functionality – it’s ultimately about convenience. And you’ll see several instances in this article 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.

    Iterating over Arrays

    for/in loops work with two basic types: arrays and collection classes (specifically, only collections that can be iterated over, as detailed in “Making Your Classes Work with for/in” described later). Arrays are the easiest to iterate over using for/in.

    Arrays have their type declared in the initialisation statement, as shown here:

    int[] int_array = new int[4];
    String[] args = new String[10];
    float[] float_array = new float[20];
    This means that you can set up your looping variable as that type and just operate upon that variable:
    public void testArrayLooping(
    		PrintStream out)
    		throws IOException {
    	int[] primes = new int[] {
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
    
    // Print the primes out using a
    // for/in loop
    	for (int n : primes) {
    		out.println(n);
    	}
    }
    This is about as easy as it gets. As a nice benefit, you don’t have to worry about the number of times to iterate, and that alone is worth getting to know this loop.

    What about iterating over object arrays? This presents no problem at all. Consider the following code:

    public void testObjectArrayLooping(
    		PrintStream out)
    		throws IOException {
    	List[] list_array = new List[3];
    
    	list_array[0] = getList( );
    	list_array[1] = getList( );
    	list_array[2] = getList( );
    
    	for (List l : list_array) {
    		out.println(l.getClass
    			( ).getName( ));
    	}
    }
    This code compiles and runs perfectly.

    Iterating over Collections

    Iterating over a collection works in just about the same way as iterating over an array. The main difference is that you’re going to have to add some type-casting, as the objects within a collection aren’t compile-time determinable, except when using generics (see the next section on Avoiding Unnecessary Typecasts for details on generics and for/in).

    Below is a simple program that shows several types of collection iteration:

    package com.oreilly.tiger.ch07;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class ForInDemo {
    
    	public static void main(String[] args) {
    // These are collections we’ll iterate over below.
    		List wordlist = new ArrayList( );
    		Set wordset = new HashSet( );
    
    // We start with a basic loop over the elements of an array.
    // The body of the loop is executed once for each element of args[].
    // Each time through one element is assigned to the variable word.
    		System.out.println(“Assigning arguments to lists...”);
    		for(String word : args) {
    			System.out.print(word + “ “);
    			wordlist.add(word);
    			wordset.add(word);
    		}
    		System.out.println( );
    
    // Iterate through the elements the List now.
    // Since lists have an order, these words should appear as above
    		System.out.println(“Printing words from wordlist “
    				+ ”(ordered, with duplicates)...”);
    		for(Object word : wordlist) {
    			System.out.print((String)word + “ “);
    		}
    	System.out.println( );
    
    // Do the same for the Set.
    // The loop looks the same but by virtue of using a Set, we lose the word
    // order and also discard duplicates.
    		System.out.println(“Printing words from wordset “
    			+ “(unordered, no duplicates)...”);
    		for(Object word : wordset) {
    			System.out.print((String)word + “ “);
    		}
    	}
    }

    When compiling this class, you’ll get several warnings from the compiler because the code doesn’t use a typed list, like List<String>. We’ll cover using generics with for/in later in the article.

    Avoiding Unnecessary Typecasts

    While for/in is nice, you still have to perform all those typecasts, as seen in the previous example. Java 1.5 introduces some pretty powerful language structures in the form of generics. The main thrust of those new structures is to increase type safety, and that, paired with what you already know about for/in, can increase the convenience of this new loop. You can get away with being specific in your loop iterations, rather than getting an Object from each iteration and then casting that Object to the appropriate type.

    The first step in working with type-specific iterators actually has to occur before you ever type for/in. You need to declare your collections using generics:

    // These are collections we’ll iterate
    // over below.
    List<String> wordlist =
    	new ArrayList<String>( );
    Set<String> wordset =
    	new HashSet<String>( );
    Then write your code normally, except substitute a type-specific variable instead of a generic Object and remove any typecasts:
    for(String word : wordlist) {
    	System.out.print(word + “ “);
    }

    Below is a generics version of the program listed above. The output is identical to that from the previous example:

    package com.oreilly.tiger.ch07;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class ForInGenericsDemo {
    	public static void main(String[] args) {
    
    // These are collections we’ll iterate over below.
    		List<String> wordlist = new ArrayList<String>( );
    		Set<String> wordset = new HashSet<String>( );
    
    // We start with a basic loop over the elements of an array.
    // The body of the loop is executed once for each element of args[].
    // Each time through one element is assigned to the variable word.
    		System.out.println(“Assigning arguments to lists...”);
    		for(String word : args) {
    			System.out.print(word + “ “);
    			wordlist.add(word);
    			wordset.add(word);
    		}
    		System.out.println( );
    
    // Iterate through the elements of the List now.
    // Since lists have an order, these words should appear as above
    		System.out.println(“Printing words from wordlist “
    			 + “(ordered, with duplicates)...”);
    		for(String word : wordlist) {
    			System.out.print(word + “ “);
    		}
    		System.out.println( );
    
    // Do the same for the Set. The loop looks the same but by virtue of
    // using a Set, we lose the word order and also discard duplicates.
    		System.out.println(“Printing words from wordset “ +
    				“(unordered, no duplicates)...”);
    		for(String word : wordset) {
    			System.out.print(word + “ “);
    		}
    	}
    }

    When using generics in this manner, you’re essentially offloading all the typecasting (and possible ClassCastExceptions) onto the compiler, rather than dealing with them at runtime. When the collections were declared, the use of generics (<String>, syntactically) allowed the compiler to limit the accepted types passed into the collections. As a nice side effect, your for/in statement can make this same assumption, and since the compiler checks all of this at compile-time, rather than runtime, your code works, and saves you some typecasting in the process.

    Making Your Classes Work with for/in

    Despite all the collection options available, there are times when it’s still useful to define your own custom objects. In cases where your objects represent some sort of collection, it’s a good practice to provide a means of letting other classes iterate over them. In the past, this usually meant ensuring that your class provided a java.util.Iterator, allowing it to work with a for loop. With Tiger, you should consider taking a few extra steps to ensure that your custom objects will work with for/in as well. In addition to working with Iterator, you’ll need to learn a new interface: java.lang.Iterable. Note that Iterable is in java.lang, not java.util, as you might expect.

    First, familiarize yourself with the next two examples, the Iterator and Iterable interfaces. You’ll need to grasp both of these to see how the various loops in Java work.

    The Iterator interface:

    package java.util;
    public interface Iterator<E> {
    	public boolean hasNext( );
    	public E next( );
    	public void remove( );
    }
    I’ve obviously stripped this down to the bare essentials; that’s all you really need, anyway. These methods should look familiar, although I still find the generics syntax (<E> and E) a bit odd to look at.

    Here’s Iterable, in the same form:

    package java.lang;
    public interface Iterable<E> {
    	public java.util.Iterator<E>
    		iterator( );
    }
    There are two basic cases in which Iterator and Iterable become issues when dealing with custom objects:
    • Your custom object extends an existing Collection class that already supports for/in.
    • Your custom object has to handle iteration manually.

    Extending collection classes

    The first case is the easiest to deal with, as you can essentially steal behaviour from the parent class to do all the work. The next example shows a simple class that extends List.
    package com.oreilly.tiger.ch07;
    
    import java.util.LinkedList;
    import java.util.List;
    
    public class GuitarManufacturerList
    		extends LinkedList<String> {
    
    	public GuitarManufacturerList( ) {
    		super( );
    	}
    
    	public boolean add(
    		String manufacturer) {
    		if (manufacturer.indexOf(
    			“Guitars”) == -1) {
    			return false;
    		} else {
    			super.add(manufacturer);
    			return true;
    		}
    	}
    }
    This class doesn’t do much in terms of customisation – it does require that only String be allowed as a parameter (through the extends LinkedList<String> declaration), and that values passed into the add( ) method have “Guitars” as part of their value. This is a rather hackish way to ensure manufacturers are supplied, but it’s useful for an illustration.

    You can now use this class. The example below creates a new instance of GuitarManufacturerList, seeds it with some sample data, and then uses for/in to iterate over it. With essentially no work on your part, you get the benefit of iteration from the superclass, LinkedList.

    package com.oreilly.tiger.ch07;
    
    import java.io.IOException;
    import java.io.PrintStream;
    
    public class CustomObjectTester {
    
    /** A custom object that extends List */
    private GuitarManufacturerList manufacturers;
    
    public CustomObjectTester( ) {
    	this.manufacturers = new GuitarManufacturerList<String>( );
    }
    
    public void testListExtension(PrintStream out) throws IOException {
    // Add some items for good measure
    	manufacturers.add(“Epiphone Guitars”);
    	manufacturers.add(“Gibson Guitars”);
    
    // Iterate with for/in
    	for (String manufacturer : manufacturers) {
    		out.println(manufacturer);
    	}
    }
    
    public static void main(String[] args) {
    	try {
    		CustomObjectTester tester = new CustomObjectTester( );
    		tester.testListExtension(System.out);
    	} catch (Exception e) {
    		e.printStackTrace( );
    	}
    	}
    }

    Handling iteration manually

    In cases where you’re not extending an existing collection class, you’ve got a little more work to do. Still, you’ll usually find yourself borrowing at least some behaviour from existing collection classes, and avoiding direct implementation of Iterator. The next example shows a simple text file reader that lists the lines of a file when iterated over. In the listing below, if you don’t pass in “LinkedList <String>” here, and just use “LinkedList”, you’ll get compiler warnings indicating a possible type mismatch.
    package com.oreilly.tiger.ch07;
    
    import java.util.Iterator;
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.io.IOException;
    
    /**
    * This class allows line-by-line iteration through a text file.
    * The iterator’s remove( ) method throws
    * UnsupportedOperatorException.
    * The iterator wraps and rethrows
    * IOExceptions as IllegalArgumentExceptions.
    */
    public class TextFile implements Iterable<String> {
    	// Used by the TextFileIterator class below
    	final String filename;
    	public TextFile(String filename) {
    		this.filename = filename;
    	}
    
    	// This is the one method of the Iterable interface
    	public Iterator<String> iterator( ) {
    		return new TextFileIterator( );
    	}
    
    	// This non-static member class is the iterator implementation
    	class TextFileIterator implements Iterator<String> {
    		// The stream we’re reading from
    		BufferedReader in;
    		// Return value of next call to next( )
    		String nextline;
    
    		public TextFileIterator( ) {
    		// Open the file and read and remember the first line.
    		// We peek ahead like this for the benefit of hasNext( ).
    			try {
    				in = new BufferedReader(new FileReader(filename));
    				nextline = in.readLine( );
    			} catch(IOException e) {
    			throw new IllegalArgumentException(e);
    			}
    		}
    
    		// If the next line is non-null, then we have a next line
    		public boolean hasNext( ) {
    			return nextline != null;
    		}
    
    		// Return the next line, but first read the line that follows it.
    		public String next( ) {
    			try {
    				String result = nextline;
    		// If we haven’t reached EOF yet
    				if (nextline != null) {
    					nextline = in.readLine( ); // Read another line
    					if (nextline == null)
    						in.close( ); // And close on EOF
    				}
    
    		// Return the line we read last time through.
    				return result;
    			} catch(IOException e) {
    				throw new IllegalArgumentException(e);
    			}
    		}
    
    		// The file is read-only; we don’t allow lines to be removed.
    		public void remove( ) {
    			throw new UnsupportedOperationException( );
    		}
    	}
    
    	public static void main(String[] args) {
    		String filename = “TextFile.java”;
    		if (args.length > 0) filename = args[0];
    		for(String line : new TextFile(filename)) System.out.println(line);
    	}
    }

    The interesting work is in the TextFile-Iterator class, which handles all the work of iteration. The first thing to notice is that this iteration is completely read-only – remove simply throws an UnsupportedOperationException. This is a perfectly legal and useful means of ensuring that programmers understand the use-case your custom classes are designed for. I’ll leave you to work through the rest of the details; the source code is pretty self-explanatory.

    Determining List Position and Variable Value

    for/in is, more than anything, about convenience. However, that comes a degree of lost flexibility. One such example is the inability to determine the position in a list that the for/in construct resides at. As your code executes within the for/in loop, there is no way to access the position in the list, and the list variable itself isn’t accessible, making its access equally impossible.

    A common iteration technique is to use the loop variable, especially if it’s numerical, in the loop body itself:

    List<String> wordList =
    	new LinkedList<String>( );
    for (int i=0; i<args.length; i++) {
    	wordList.add(“word “ + (i+1) + “:
    		‘“ + args[i] + “‘“);
    }
    This is perfectly legitimate, and really useful if you’re performing some sort of count. However, it’s impossible to access the iterator in a for/in loop, as that’s kept internal (and not even generated until compilation takes place). In this case, you’re out of luck. You can use for/in to display the results of a situation like this, but not to make the assignment itself:
    public void determineListPosition(
    	PrintStream out, String[] args)
    	throws IOException {
    	List<String> wordList =
    		new LinkedList<String>( );
    	for (int i=0; i<args.length; i++) {
    		wordList.add(“word “ + (i+1) +
    			“: ‘“ + args[i] + “‘“);
    	}
    	for (String word : wordList) {
    		out.println(word);
    	}
    }
    This is hardly a severe limitation, but it’s one you should be aware of.

    Another common usage of lists is String concatenation, and that illustrates another of the for/in limitations. It’s common in String concatenation to add separators between all but the last of a set of words, such as when printing a list. This separator is often a comma or perhaps a space:

    StringBuffer longList =
    	new StringBuffer( );
    for (int i = 0, len=wordList.size( );
    	i < len; i++) {
    	if (i < (len-1)) {
    		longList.append(
    			wordList.get(i))
    			.append(“, “);
    	} else {
    		longList.append(
    			wordList.get(i));
    	}
    }
    out.println(longList);
    Here, all but the last word in the list has a comma appended to it, while the last one is appended without a comma. This makes for a nice list output. However, this rather simple task is impossible with for/in, because the variable that is used to do all the work, i, is inaccessible in a for/in loop. Again, a fairly minor inconvenience, but it’s certainly not time to retire our old friend for just yet.

    Removing List Items in a for/in Loop

    Another common task in loop iteration, particularly over collections, is inloop modification. This is all done through the iterator, as directly modifying the collection creates all sorts of nasty loop problems. Instead, using methods such as remove( ) from java.util.Iterator allows modifications in a loop-safe way. However, since the iterator is hidden in for/in, this is another limitation of for/in.

    This is another one of those “You can’t” recipes. To see exactly what it is you can’t do, take a look at the following code:

    public void removeListItems(
    	PrintStream out, String[] args)
    			throws IOException {
    
    	List<String> wordList =
    		new LinkedList<String>( );
    // Assign some words
    	for (int i=0; i<args.length; i++) {
    		wordList.add(“word “ + (i+1) +
    				“: ‘“ + args[i] + “‘“);
    	}
    
    // Remove all words with “1” in them.
    // Impossible with for/in
    	for (Iterator i =
    		wordList.iterator( );
    		i.hasNext( ); ) {
    		String word =
    			(String)i.next( );
    		if (word.indexOf(“1”) != -1) {
    			i.remove( );
    		}
    	}
    
    // You can print the words using
    // for/in
    	for (String word : wordList) {
    		out.println(word);
    	}
    }
    In particular, notice the second for loop, which uses remove( ) to yank any words in the List with “1” in the text. This depends on the usage of Iterator, which isn’t available in for/in, so you’re out of luck here.

    What about anything else that involves knowing where you are in the list? Nope – it’s not possible. Here are just a few examples of other things you can’t do with for/in:

    • Iterate backward through the elements of an array or List.
    • Use a single loop counter to access similarly numbered or positioned elements in two distinct arrays or collections.
    • Iterate through the elements of a List using calls to get() rather than calls to its iterator.
    Watch out for this last one – it is a legitimate performance concern. For the java.util.ArrayList class, for example, looping with the size( ) and get( ) methods is measurably faster than using the list’s Iterator. In many cases, the performance difference is negligible and irrelevant. But, when writing an inner loop or other performance-critical code, you might prefer to use a for loop with the get( ) method instead of a for/in loop._


    This article is based on Chapter 7 of Java 1.5 Tiger: A Developer’s Notebook by David Flanagan and Brett McLaughlin published by O’Reilly, ISBN: 0596007388.

    You might also like...

    Comments

    Contribute

    Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

    Our tools

    We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

    “Debugging is anticipated with distaste, performed with reluctance, and bragged about forever.” - Dan Kaminsky