Iterate an Enumeration in Java 8

JavaLambdaIterationEnumerationJava 8

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

(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);

Solution 2 - Java

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(...));

Solution 3 - Java

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

nets.asIterator().forEachRemaining(iface -> { ... });

Solution 4 - Java

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)…

Solution 5 - Java

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

Solution 6 - Java

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

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

Solution 7 - Java

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();
        }
    };
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTapas BoseView Question on Stackoverflow
Solution 1 - JavaPshemoView Answer on Stackoverflow
Solution 2 - JavanosidView Answer on Stackoverflow
Solution 3 - JavaTagir ValeevView Answer on Stackoverflow
Solution 4 - JavaHolgerView Answer on Stackoverflow
Solution 5 - JavaArne BurmeisterView Answer on Stackoverflow
Solution 6 - JavaMarek GregorView Answer on Stackoverflow
Solution 7 - Javauser579013View Answer on Stackoverflow