Looping through a collection of objects and doing something with each object is one of the most common programming idioms a Java developer can face. You’ve no doubt coded such loops many times. The following sample shows how to iterate over an array with a for loop in Java:
List names = new ArrayList(); names.add("a"); names.add("b"); names.add("c"); for (Iterator it = names.iterator(); it.hasNext(); ) { String name = (String)it.next(); System.out.println(name.charAt(0)); }
Instead of using a for
loop, you might have used a
while
loop to loop through an array. You might have used an Enumeration, instead of an
Iterator, if you were working with the older Vector class. Or, you might have
used a for
loop and a counter, accessing each element using the
get(int index)
method of the List interface.
If you were to use an array, this is how you would typically iterate through
each of its elements:
String[] moreNames = { "d", "e", "f" }; for (int i = 0; i < moreNames.length; i++) System.out.println(moreNames[i].charAt(0));
It’s not difficult to iterate through a collection, but it is a very
repetitive operation. Iteration requires you to type a good amount of
characters. Granted, the template feature of most Integrated Development Environments (IDEs) will eliminate your need to type so much. But, as you saw, there are many ways to iterate through a loop.
The existence of several different iteration techniques costs you more time.
For each iteration you encounter, you must spend a few extra seconds digesting
the iteration form. If it deviates from the form you’re used to seeing, you must
examine it even closer. Why did the developer choose to code the iteration
differently?
It’s also easy to make a mistake in coding your iterator. Ever accidentally
coded something like this?
List names = new ArrayList(); names.add("a"); names.add("b"); names.add("c"); for (Iterator it = names.iterator(); it.hasNext(); ) { String name = (String)it.next(); System.out.println(((String)it.next()).charAt(0)); }
I have. In a small section of code, it’s easy to spot the error. In a larger section of code, it’s not as easy to spot.
How to use the foreach Loop in Java
Java 1.5 introduced a new way of iterating over a collection of objects. The
foreach loop is also known as the enhanced for loop. It is a new syntactical
construct designed to simplify iteration. The foreach loop should make iteration
more consistent, but only if and when everyone starts using it.
Effective use of the foreach loop depends on using Java’s parameterized
types, also known as generics. So that you can understand the code in this
article, I’ll explain how to use parameterized types.
Here is how you might construct and iterate a list of names in Java:
List<String> names = new ArrayList<String>(); names.add("a"); names.add("b"); names.add("c"); for (String name: names) System.out.println(name.charAt(0));
There are two important things in this bit of code: first, the use of a generic list, and second, the use of the new foreach loop.
To construct an object of the parameterized ArrayList type, you bind
the ArrayList to a class. In the example, you bind the ArrayList to the String
class. You also bind the List reference to the String class. You are now
restricted to adding only String objects to the list. If you insert, for
example, a Date object in the names
collection, your code will not
compile. When you retrieve objects from the list, you need not cast. Java knows
that the list contains only String objects. It does the casting for you, behind
the scenes.
Once you have stored objects in a parameterized List, you can iterate through
them using the foreach loop:
for (String name: names)
You read this statement as, “for each String name in names.” The Java VM
executes the body of the foreach loop once for each object in the
names
collection. Each time through the loop, Java assigns the next
object in turn to a local reference variable called name
. You must
declare this reference variable as a String type–the type to which you bound
the names
collection.
The foreach loop is succinct. There is no need to cast; Java does the cast
for you. You can use the name
reference within the body of the loop
as a String reference. You cannot use the name
reference outside
the body of the foreach loop.
How to Use Foreach Loops with Arrays in Java
You saw how the foreach loop allows you to iterate over collection class
types. Sun also modified Java to allow you to iterate through arrays using
foreach. The syntax is exactly the same:
String[] moreNames = { "d", "e", "f" }; for (String name: moreNames) System.out.println(name.charAt(0));
Supporting Foreach in Your Own Class
Suppose you are building a Catalog class. A Catalog object collects any
number of Product objects. You store these objects using an ArrayList instance
variable defined in Catalog. Code working with a Catalog object will frequently
need to iterate through the entire list of products, to do something with each
object in turn.
Here is how the Catalog class might look:
import java.util.*; class Catalog { private List<Product> products = new ArrayList<Product>(); void add(Product product) { products.add(product); } }
The Product class includes a method that allows you to discount the price on
a product:
class Product { private String id; private String name; private BigDecimal cost; Product(String id, String name, BigDecimal cost) { this.id = id; this.name = name; this.cost = cost; } void discount(BigDecimal percent) { cost = cost.multiply(new BigDecimal("1.0").subtract(percent)); } public String toString() { return id + ": " + name + " @ " + cost; } }
A (Poor) Solution
To allow client code to work with all products, you could create a method in
Catalog that returned the ArrayList of products:
// don't do this List<Product> getProducts() { return products; }
Client code could iterate through the list however they chose. However,
returning a collection to a client is a bad idea. By giving the client
your collection, you have relinquished any control over the contents of that
collection. Client code could add or remove elements to the collection without
the knowledge of the Catalog object. You’ve also burdened the client with more
work than necessary.
The Iterable Interface
Instead, you can designate the Catalog class as being “iterable.” Making a
class iterable tells clients that they can iterate through its contents using a
foreach loop. Sun has added to Java a new interface, java.lang.Iterable, that
allows you to mark your classes as iterable:
package java.lang; import java.util.Iterator; public interface Iterable<T> { Iterator<T> iterator(); }
To implement this interface in Catalog, you must code an
iterator
method. This method must return an Iterator object that is
bound to the Product type.
The Catalog class stores all of its Product objects in an ArrayList. The
easiest way to provide an Iterator object to a client is to simply return the
Iterator object from the products
ArrayList itself. Here is the
modified Catalog class:
class Catalog implements Iterable<Product> { private List<Product> products = new ArrayList<Product>(); void add(Product product) { products.add(product); } public Iterator<Product> iterator() { return products.iterator(); } }
Note that the Iterator, the List reference, and the ArrayList are all
bound to the Product type.
Once you have implemented the java.lang.Iterable interface, client code can
use the foreach loop. Here is a bit of example code:
Catalog catalog = new Catalog(); catalog.add(new Product("1", "pinto", new BigDecimal("4.99"))); catalog.add(new Product("2", "flounder", new BigDecimal("64.88"))); catalog.add(new Product("2", "cucumber", new BigDecimal("2.01"))); for (Product product: catalog) product.discount(new BigDecimal("0.1")); for (Product product: catalog) System.out.println(product);
Summary of How to Use Java foreach Loops
The foreach loop provides a simple, consistent solution for iterating arrays,
collection classes, and even your own collections. It eliminates much of the
repetitive code that you would otherwise require. The foreach loop eliminates
the need for casting as well as some potential problems. The foreach loop is a
nice new addition to Java that was long overdue. I greatly appreciate the added
simplicity in my source code.
Jeff Langr is a freelance author and the owner of Langr Software Solutions. He is working on a second book on Java and test-driven development entitled Agile Java, due
out from Prentice Hall in fall 2004.