Java for each loop

jdavidb on 2008-07-09T13:49:41

I'm figuring out something about the new Java for each loop. As I noted, this new construct allows you to use for to iterate over 1) arrays, and 2) anything that implements the Iterable interface.

Where the confusion here sets in for me is that #2 is not "allows you to use for to iterate over an Iterator." There's quite a distinction there. :) An Iterator is an object that allows you to use hasNext() and next() methods to traverse over a collection of objects. An Iterable object is one which provides a method called iterator() which returns an Iterator() for that set.

So I'm dealing with an API that gives me three methods that return Enumerations full of interesting stuff and one method that returns an Iterator full of interesting stuff. (Silly design; they should all be one or the other, and my understanding is the modern way to do this is with Iterators.) And I'd like to plug them all into a nice method with a for each loop to do something with them, but I can't since I can't use the for each loop on either Enumerations or Iterators, directly. And I'd still like to write one routine to deal with all of these, but the methods to call to traverse Enumerations are not the same as the ones for Iterators.

If I could find a nice way to create a Collection of any type directly from Enumerations and Iterators, without having to code it myself, that would make this much cleaner. All Collections apparently implement the Iterable interface. But this is really getting silly; the whole point of having an Iterator is you've already pulled it out of the relevant Collection and shouldn't have to deal with it again. How much would it take for Java's for loop to just support Enumerations and Iterators?


Cheat!

ferreira on 2008-07-10T01:43:49

When writing Java, remember it is not flexible. You, as the programmer, should be one to show flexibility. Then, cheat. For example, if you have control on the generated iterator, make a class which implements Iterator and Iterable. Delegate or inherit the methods of Iterator and do

public Iterator iterator() {
    return this;
}

Prety stupid, but it may work. For Enumerations, you'll have to write an adapter from enumerations to iterations (if you can't find one in the forest of classes available in the JDK). Of course, all of this has much more code that any of us would want to write, but it is hard to escape from that usually.

Re:Cheat!

jdavidb on 2008-07-10T13:46:41

When writing Java, remember it is not flexible.

Don't worry; I've never forgotten this. :)

enumerations at least

lachoy on 2008-07-10T03:24:15

At least for an enumeration you can do:

for ( Foo f : Collections.list( enumeration ) ) {
   ...
}

I suspect that, despite how much sense it makes, they didn't make the Iterator interface extend Iterable because it would break compatibility with a ton of custom Iterators people have coded in the years since Java 1.2. Java is extremely wary of doing this, even when doing differently (like with generics) winds up causing people pain for years.

As it is, it's pretty easy to create a wrapper class to do what ferreira suggested above, or to code something similar to the static Collections methods to consume the Iterator and return a List. Of course, if the Iterator is of the infinite variety, you might be in trouble :-)

Re:enumerations at least

jdavidb on 2008-07-10T13:48:26

Collections.list( enumeration )

Awesome! That is the glue I searched for in vain yesterday. Unfortunately it's too late for this particular project, but you can never have too much glue lying around for future tasks. :)