69

In Java 5 and above you have the foreach loop, which works magically on anything that implements Iterable:

for (Object o : list) {
  doStuff(o);
}

However, Enumerable still does not implement Iterable, meaning that to iterate over an Enumeration you must do the following:

for(; e.hasMoreElements() ;) {
  doStuff(e.nextElement());
}

Does anyone know if there is a reason why Enumeration still does not implement Iterable?

Edit: As a clarification, I'm not talking about the language concept of an enum, I'm talking a Java-specific class in the Java API called 'Enumeration'.

Adam Parkin
  • 17,891
  • 17
  • 66
  • 87
SCdF
  • 57,260
  • 24
  • 77
  • 113

6 Answers6

82

As an easy and clean way of using an Enumeration with the enhanced for loop, convert to an ArrayList with java.util.Collections.list.

for (TableColumn col : Collections.list(columnModel.getColumns()) {

(javax.swing.table.TableColumnModel.getColumns returns Enumeration.)

Note, this may be very slightly less efficient.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 4
    Funny: this (columns in the column model) is the exact reason I found this question. – Dave Apr 20 '11 at 18:03
50

It doesn't make sense for Enumeration to implement Iterable. Iterable is a factory method for Iterator. Enumeration is analogous to Iterator, and only maintains state for a single enumeration.

So, be careful trying to wrap an Enumeration as an Iterable. If someone passes me an Iterable, I will assume that I can call iterator() on it repeatedly, creating as many Iterator instances as I want, and iterating independently on each. A wrapped Enumeration will not fulfill this contract; don't let your wrapped Enumeration escape from your own code. (As an aside, I noticed that Java 7's DirectoryStream violates expectations in just this way, and shouldn't be allowed to "escape" either.)

Enumeration is like an Iterator, not an Iterable. A Collection is Iterable. An Iterator is not.

You can't do this:

Vector<X> list = …
Iterator<X> i = list.iterator();
for (X x : i) {
    x.doStuff();
}

So it wouldn't make sense to do this:

Vector<X> list = …
Enumeration<X> i = list.enumeration();
for (X x : i) {
    x.doStuff();
}

There is no Enumerable equivalent to Iterable. It could be added without breaking anything to work in for loops, but what would be the point? If you are able to implement this new Enumerable interface, why not just implement Iterable instead?

erickson
  • 265,237
  • 58
  • 395
  • 493
41

Enumeration hasn't been modified to support Iterable because it's an interface not a concrete class (like Vector, which was modifed to support the Collections interface).

If Enumeration was changed to support Iterable it would break a bunch of people's code.

Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
  • 11
    Still, given that there is for-each support for **both** Iterable **and** arrays, why didn't sun include Enumerable as well? – akuhn Nov 26 '08 at 16:13
  • 8
    @Adrian Kuhn: they didn't include for-each support for Iterator, and Enumerable behaves like an Iterator, not an Iterable. – Laurence Gonsalves Aug 06 '09 at 16:43
  • 4
    Enumeration is not IteraBLE. Enumeratrion is actually IteraTOR (but without 'delete') http://stackoverflow.com/a/8197868/117220. With this clarification the answer is that this would break existing APIs. It would be possible to do this backwards-compatibly if partial implementation is allowed in Interfaces (like in Scala traits). – Petr Gladkikh Jun 01 '12 at 03:49
  • @PetrGladkikh: Yet they still didn't fix it in Java 8. – JohnEye Jun 09 '15 at 13:51
  • 1
    @JohnEye Even with default methods in Java 8, it's not possible to fully implement an `Enumeration`-based `Iterable`. There's nothing to "fix"; `Enumeration` and `Iterable` are not logically equivalent types, and a conversion utility to correctly bridge the gap between them is already provided in `Collections.list()` – erickson Jun 09 '17 at 13:40
7

AFAIK Enumeration is kinda "deprecated":

Iterator takes the place of Enumeration in the Java collections framework

I hope they'll change the Servlet API with JSR 315 to use Iterator instead of Enumeration.

dlinsin
  • 19,249
  • 13
  • 42
  • 53
3

If you would just like it to be syntactically a little cleaner, you can use:

while(e.hasMoreElements()) {
  doStuff(e.nextElement());
}
2

It is possible to create an Iterable from any object with a method that returns an Enumeration, using a lambda as an adapter. In Java 8, use Guava's static Iterators.forEnumeration method, and in Java 9+ use the Enumeration instance method asIterator.

Consider the Servlet API's HttpSession.getAttributeNames(), which returns an Enumeration<String> rather than an Iterator<String>.

Java 8 using Guava

Iterable<String> iterable = () -> Iterators.forEnumeration(session.getAttributeNames());

Java 9+

Iterable<String> iterable = () -> session.getAttributeNames().asIterator();

Note that these lambdas are truly Iterable; they return a fresh Iterator each time they are invoked. You can use them exactly like any other Iterable in an enhanced for loop, StreamSupport.stream(iterable.spliterator(), false), and iterable.forEach().

The same trick works on classes that provide an Iterator but don't implement Iterable. Iterable<Something> iterable = notIterable::createIterator;

Clement Cherlin
  • 387
  • 6
  • 13