在Java 8中迭代枚举

Tap*_*ose 70 java iteration lambda enumeration java-8

是否可以Enumeration使用Lambda Expression 进行迭代?以下代码片段的Lambda表示形式是什么:

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

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

}
Run Code Online (Sandbox Code Playgroud)

我没有在其中找到任何流.

Psh*_*emo 86

(这个答案显示了很多选项中的一个.只是因为它接受标记,并不意味着它是最好的.我建议阅读其他答案并根据你所处的情况选择一个.就个人而言,我发现Holger的答案最好的,因为它也很简单,但不需要额外的迭代 - 这在我的解决方案中发生.但对于Java 9解决方案,请访问Tagir Valeev回答)


您可以将元素从您复制EnumerationArrayList,Collections.list然后使用它

Collections.list(yourEnumeration).forEach(yourAction);
Run Code Online (Sandbox Code Playgroud)

  • 问题是,现在您必须将所有元素存储在列表中.如果它很小,可能就好了.但值得一提的是,因为有时它会太大而无法适应记忆. (16认同)
  • @Filip您的评论是关于[`Enum`](https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html),但问题是关于[`Enumeration`](https: //docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html). (3认同)

nos*_*sid 51

如果代码中有很多Enumerations,我建议创建一个静态帮助器方法,将Enumeration转换为Stream.静态方法可能如下所示:

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);
}
Run Code Online (Sandbox Code Playgroud)

将该方法与静态导入一起使用.与Holger的解决方案相比,您可以从不同的操作中受益,这可能使现有代码更简单.这是一个例子:

Map<...> map = enumerationAsStream(enumeration)
    .filter(Objects::nonNull)
    .collect(groupingBy(...));
Run Code Online (Sandbox Code Playgroud)

  • 这怎么不是 JDK 的一部分呢? (2认同)
  • @ThomasFritsch 的提案制作了列表的中间副本,这是要避免的。 (2认同)

Tag*_*eev 45

从Java-9开始,将有一个新的默认方法Enumeration.asIterator(),它将使纯Java解决方案更简单:

nets.asIterator().forEachRemaining(iface -> { ... });
Run Code Online (Sandbox Code Playgroud)


Hol*_*ger 34

如果您不喜欢在Collections.list(Enumeration)迭代开始之前将整个内容复制到(临时)列表中的事实,您可以使用一个简单的实用方法来帮助自己:

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

然后你可以简单地做forEachRemaining(enumeration, lambda-expression);(注意import static功能)......


Arn*_*ter 11

您可以使用以下标准功能组合:

StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel)
Run Code Online (Sandbox Code Playgroud)

您还可以添加更多的特征,如NONNULLDISTINCT.

应用静态导入后,这将变得更具可读性:

stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)
Run Code Online (Sandbox Code Playgroud)

现在你有一个标准的Java 8 Stream以任何方式使用!您可以通过true并行处理.

要从Enumeration转换为Iterator,请使用以下任意一项:

  • CollectionUtils.toIterator() 从Spring 3.2或者你可以使用
  • IteratorUtils.asIterator() 来自Apache Commons Collections 3.2
  • Iterators.forEnumeration() 来自Google Guava


Mar*_*gor 7

对于Java 8,枚举到流的最简单的转换是:

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


use*_*013 5

我知道这是一个老问题,但我想提出 Collections.asList 和 Stream 功能的替代方案。由于问题的标题是“迭代枚举”,我认识到有时您想要使用 lambda 表达式,但增强的 for 循环可能更可取,因为枚举对象可能会抛出异常,并且 for 循环更容易封装在更大的 try 中 - catch 代码段(lambda 要求在 lambda 内捕获已声明的异常)。为此,这里使用 lambda 创建一个可在 for 循环中使用的 Iterable,并且不会预加载枚举:

 /**
 * 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();
        }
    };
}
Run Code Online (Sandbox Code Playgroud)