78

Why can't I do:

Enumeration e = ...
for (Object o : e)
  ...
cletus
  • 616,129
  • 168
  • 910
  • 942
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 5
    Enumeration was replaced by Iterator in Java 1.2 in 1998 and is retained for legacy support. The real question is why you want to use it. Possibly because you use a library which forces you to do so? – Peter Lawrey Aug 27 '10 at 21:57
  • 2
    @Peter - yes, an external library is the answer. – ripper234 Aug 29 '10 at 20:19

8 Answers8

65

Because Enumeration<T> doesn't extend Iterable<T>. Here is an example of making Iterable Enumerations using the adapter pattern.

As to why that's an interesting question. This isn't exactly your question but it sheds some light on it. From the Java Collections API Design FAQ:

Why doesn't Iterator extend Enumeration?

We view the method names for Enumeration as unfortunate. They're very long, and very frequently used. Given that we were adding a method and creating a whole new framework, we felt that it would be foolish not to take advantage of the opportunity to improve the names. Of course we could support the new and old names in Iterator, but it doesn't seem worthwhile.

That basically suggests to me that Sun wants to distance themselves from Enumeration, which is very early Java with quite a verbose syntax.

M. Justin
  • 14,487
  • 7
  • 91
  • 130
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 26
    Next question: why aren't Enumerations Iterable? http://stackoverflow.com/questions/27240/why-arent-enumerations-iterable – Michael Myers Aug 06 '09 at 16:37
  • 1
    Is there a semantic difference between the two? (I'm not familiar with the Iterable class)? Why not have for work on Enumeration as well? – ripper234 Aug 06 '09 at 16:37
  • 5
    Because Enumerations are more akin to Iterator, not Iterable (see the stackoverflow question mmyers posted). As a workaround, you can do `for(; e.hasMoreElements(); ) { e.getNextElement(); }` – Tim Aug 06 '09 at 16:40
  • 4
    But `Iterators` are not `Iterable` either. You can't do `for (obj : itr)`. The reason for this is that `Iterable` is really *repeatedly iterable*, whereas an iterator can only be iterated over once. – oxbow_lakes Aug 06 '09 at 17:06
  • 1
    Do you mean "Enumeration doesnt Implement Iterably" instead of extends? – Jimmy Aug 26 '10 at 16:26
  • 4
    This doesn't explain why Sun/Oracle didn't allow an `Enumeration` in the new `for` syntax as well as an `Iterable` and an `array`. – mjaggard Apr 02 '13 at 13:57
  • [here](https://stackoverflow.com/a/46674/822870) is a one line "fix" to use an Enumeration in an enhanced for loop ("foreach") – David Balažic Apr 29 '19 at 08:53
50

Using the Collections utility class, Enumeration can be made iterable like:

Enumeration headerValues=request.getHeaders("mycustomheader");
List headerValuesList=Collections.list(headerValues);

for(Object headerValueObj:headerValuesList){
 ... do whatever you want to do with headerValueObj
}

This uses the Collections.list method, which copies the Enumeration data into a new ArrayList.

Returns an array list containing the elements returned by the specified enumeration in the order they are returned by the enumeration. This method provides interoperability between legacy APIs that return enumerations and new APIs that require collections.

M. Justin
  • 14,487
  • 7
  • 91
  • 130
user1555669
  • 501
  • 4
  • 3
  • 6
    The elements are copied in a new list before starting the iteration, this solution should be avoided for long enumerations. The solutions turning an Enumeration into an Iterator have less memory overhead. – Emmanuel Bourg Dec 18 '14 at 09:21
  • @EmmanuelBourg but they have side effects, as enumerations are stateful. – P.Péter Mar 17 '16 at 10:39
  • 1
    This is by far the easiest answer! No dependencies needed, and clearly readable. Thanks! – Geert Schuring Mar 30 '16 at 12:26
8

I have solved this problem with two very simple classes, one for Enumeration and one for Iterator. The enumeration wrapper is as follows:

static class IterableEnumeration<T>
extends Object
implements Iterable<T>, Iterator<T>
{
private final Enumeration<T>        enumeration;
private boolean                     used=false;

IterableEnumeration(final Enumeration<T> enm) {
    enumeration=enm;
    }

public Iterator<T> iterator() {
    if(used) { throw new IllegalStateException("Cannot use iterator from asIterable wrapper more than once"); }
    used=true;
    return this;
    }

public boolean hasNext() { return enumeration.hasMoreElements(); }
public T       next()    { return enumeration.nextElement();     }
public void    remove()  { throw new UnsupportedOperationException("Cannot remove elements from AsIterator wrapper around Enumeration"); }
}

Which can be used either with a static utility method (which is my preference):

/**
 * Convert an `Enumeration<T>` to an `Iterable<T>` for a once-off use in an enhanced for loop.
 */
static public <T> Iterable<T> asIterable(final Enumeration<T> enm) {
    return new IterableEnumeration<T>(enm);
    }

...

for(String val: Util.asIterable(enm)) {
    ...
    }

or by instantiating the class:

for(String val: new IterableEnumeration<String>(enm)) {
    ...
    }
Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189
5

The new-style-for-loop ("foreach") works on arrays, and things that implement the Iterable interface.

It's also more analogous to Iterator than to Iterable, so it wouldn't make sense for Enumeration to work with foreach unless Iterator did too (and it doesn't). Enumeration is also discouraged in favor of Iterator.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
4

With java 8 and beyond this is possible:

import java.util.Collections;
import java.util.Enumeration;

Enumeration e = ...;
Collections.list(e).forEach(o -> {
    ... // use item "o"
});
slartidan
  • 20,403
  • 15
  • 83
  • 131
1

Enumeration doesn't implement Iterable and as such can't be used directly in a foreach loop. However using Apache Commons Collections it's possible to iterate over an enumeration with:

for (Object o : new IteratorIterable(new EnumerationIterator(e))) {
    ...
}

You could also use a shorter syntax with Collections.list() but this is less efficient (two iterations over the elements and more memory usage) :

for (Object o : Collections.list(e))) {
    ...
}
Emmanuel Bourg
  • 9,601
  • 3
  • 48
  • 76
  • do you mean [IteratorIterable](http://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/iterators/IteratorIterable.html) ? – luckyluke Nov 04 '16 at 21:13
1

The Enumeration legacy class is analogous to the modern Iterator class. Both represent a current iteration over data.

The enhanced for loop was designed to work with Iterable and arrays, but notably not with Iterator. Iterable provides an iterator method, which returns an Iterator over its data.

While it isn't possible to use the enhanced for loop with Enumeration or its modern Iterator equivalent, the forEachRemaining method in Iterator (added in Java 8) provides similar functionality. Combining with Enumeration.asIterator (added in Java 9) allows iterating over an enumeration in a similar manner as the enhanced for loop:

Enumeration<Object> e = ...
e.asIterator().forEachRemaining(o -> {
  // ...
});
M. Justin
  • 14,487
  • 7
  • 91
  • 130
0

Because an Enumeration (and most classes derived from this interface) does not implement Iterable.

You can try to write your own wrapper class.

Stroboskop
  • 4,327
  • 5
  • 35
  • 52
  • 2
    You shouldn't write a wrapper for Enumeration that turns it into an Iterable any more than you should create such a wrapper for Iterator. Iterator and Enumeration objects are stateful with respect to iteration. Iterables are not. – Laurence Gonsalves Aug 06 '09 at 19:40
  • 1
    @LaurenceGonsalves Surprisingly enough, while that appears to be the pattern (and a good pattern to continue to follow), there doesn't appear to be any documented restriction that an `Iterable` needs to be able to statelessly produce `Iterators`. – M. Justin May 15 '23 at 15:28