80

Is it possible to iterate an Enumeration by using Lambda Expression? What will be the Lambda representation of the following code snippet:

Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();

while (nets.hasMoreElements()) {
    NetworkInterface networkInterface = nets.nextElement();

}

I didn't find any stream within it.

Tapas Bose
  • 28,796
  • 74
  • 215
  • 331
  • 7
    Enumerations were replaced by Iterators in Java 1.2 in 1998. It is unfortunate you still have to use it. :| – Peter Lawrey Apr 24 '14 at 06:56
  • 1
    You can adapt your Enumeration to Iterator: http://stackoverflow.com/questions/5007082/treat-enumerationt-as-iteratort – marcinj Apr 24 '14 at 06:59
  • 8
    @PeterLawrey Iterator came along, but there are still core APIs which use Enumeration. Generics came along, but there are still core APIs which use bare types or return Object. Lambdas came along, but Swing is still full of multi-method interfaces, so we can't use them. It doesn't really surprise me anymore when I find APIs which Java forgot to modernise; it just saddens me. – Hakanai Aug 18 '14 at 07:01
  • 3
    @Trejkaz Yes, Swing still uses Vector and Hashtable. – Peter Lawrey Aug 18 '14 at 13:49
  • 1
    @PeterLawrey the Servlet API still uses Enumerations. – OrangeDog Oct 30 '18 at 13:57

7 Answers7

99

(This answer shows one of many options. Just because is has had acceptance mark, doesn't mean it is the best one. I suggest reading other answers and picking one depending on situation you are in. IMO:

  • for Java 8 Holger's answer is nicest, because aside from being simple it doesn't require additional iteration which happens in my solution.
  • for Java 9 I would pick solution describe in Tagir Valeev answer)

You can copy elements from your Enumeration to ArrayList with Collections.list and then use it like

Collections.list(yourEnumeration).forEach(yourAction);
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • 18
    The catch is that now you have to store all the elements in a list. Which if it's small, is probably fine. But it's worth mentioning, because sometimes it will be too big to fit in memory. – Hakanai Aug 18 '14 at 07:02
  • How about java.util.stream.Stream#of(yourEnumeration.values()).forEach()? – Filip Dec 06 '16 at 12:16
  • 4
    @Filip Your comment is about [`Enum`](https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html) but question is about [`Enumeration`](https://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html). – Pshemo Dec 06 '16 at 13:18
52

If there are a lot of Enumerations in your code, I recommend creating a static helper method, that converts an Enumeration into a Stream. The static method might look as follows:

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            new Iterator<T>() {
                public T next() {
                    return e.nextElement();
                }
                public boolean hasNext() {
                    return e.hasMoreElements();
                }
            },
            Spliterator.ORDERED), false);
}

Use the method with a static import. In contrast to Holger's solution, you can benefit from the different stream operations, which might make the existing code even simpler. Here is an example:

Map<...> map = enumerationAsStream(enumeration)
    .filter(Objects::nonNull)
    .collect(groupingBy(...));
nosid
  • 48,932
  • 13
  • 112
  • 139
52

Since Java-9 there will be new default method Enumeration.asIterator() which will make pure Java solution simpler:

nets.asIterator().forEachRemaining(iface -> { ... });
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
42

In case you don’t like the fact that Collections.list(Enumeration) copies the entire contents into a (temporary) list before the iteration starts, you can help yourself out with a simple utility method:

public static <T> void forEachRemaining(Enumeration<T> e, Consumer<? super T> c) {
  while(e.hasMoreElements()) c.accept(e.nextElement());
}

Then you can simply do forEachRemaining(enumeration, lambda-expression); (mind the import static feature)…

Holger
  • 285,553
  • 42
  • 434
  • 765
12

You can use the following combination of standard functions:

StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel)

You may also add more characteristics like NONNULL or DISTINCT.

After applying static imports this will become more readable:

stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)

now you have a standard Java 8 Stream to be used in any way! You may pass true for parallel processing.

To convert from Enumeration to Iterator use any of:

  • CollectionUtils.toIterator() from Spring 3.2 or you can use
  • IteratorUtils.asIterator() from Apache Commons Collections 3.2
  • Iterators.forEnumeration() from Google Guava
Basilevs
  • 22,440
  • 15
  • 57
  • 102
Arne Burmeister
  • 20,046
  • 8
  • 53
  • 94
8

For Java 8 the simplest transformation of enumeration to stream is:

Collections.list(NetworkInterface.getNetworkInterfaces()).stream()

Marek Gregor
  • 3,691
  • 2
  • 26
  • 28
5

I know this is an old question but I wanted to present an alternative to Collections.asList and Stream functionality. Since the question is titled "Iterate an Enumeration", I recognize sometimes you want to use a lambda expression but an enhanced for loop may be preferable as the enumerated object may throw an exception and the for loop is easier to encapsulate in a larger try-catch code segment (lambdas require declared exceptions to be caught within the lambda). To that end, here is using a lambda to create an Iterable which is usable in a for loop and does not preload the enumeration:

 /**
 * Creates lazy Iterable for Enumeration
 *
 * @param <T> Class being iterated
 * @param e Enumeration as base for Iterator
 * @return Iterable wrapping Enumeration
 */
public static <T> Iterable<T> enumerationIterable(Enumeration<T> e)
{
    return () -> new Iterator<T>()
    {
        @Override
        public T next()
        {
            return e.nextElement();
        }

        @Override
        public boolean hasNext()
        {
            return e.hasMoreElements();
        }
    };
}
user579013
  • 197
  • 2
  • 9