Visiting Every Element

Suppose we run a mailing list. We keep the subscribers’ email addresses in a Set<String>, so that no address is on the list twice and nobody gets the same newsletter twice. To send out a newsletter, we have to send it to every address in the set. Other tasks need the same thing, such as counting how many addresses end in @jhu.edu or writing all the addresses to a file. Each of these tasks has to look at every element of the set exactly once.

Now try to do it with the operations we have. With a list we would loop over the indices and call get(i), but a set has no positions, so it has no get. The other operations, add, remove, contains, and size, do not return an element either. So right now there is no way to get the elements out of the set at all.

Java has a second form of the for loop that makes tasks like these easy to write. The form you already know uses a counter that goes over a range of indices, and you get each element by its index:

for (int i = 0; i < emails.length; i++) {
  sendNewsletter(emails[i]);
}

The other form, called the enhanced for loop, iterates over the elements of a collection directly:

for (String email : subscribers) {
  sendNewsletter(email);
}

Read it as “for each email in subscribers.” The body runs once for every element of the collection, with email set to a different element each time around. There is no index variable, no length, and no get.

The enhanced for loop already works for arrays and for Java’s own collections, such as ArrayList (that is, Java’s ArrayList and not the one we developed in earlier chapters). We want it to work for our Set too, so we can write tasks like sending the newsletter in the same short way.

But this loop does not even compile for our Set. The enhanced for loop is not a special case built into the language for arrays and library types. It is shorthand: the compiler expands it into ordinary method calls. Our Set does not provide those methods, so the loop does not compile. In this chapter, we look at what those methods are and how to supply them. Then we look at what else we can do once our Set has them. We start by making the loop work for our Set:

Set<String> subscribers = new ArraySet<>();
// add some email addresses to the set

// The following code does not compile yet, but it will after we finish this chapter.
for (String email : subscribers) {
  sendNewsletter(email);
}