在 Java8中迭代枚举

可以使用 Lambda 表达式迭代 Enumeration吗?下面代码片段的 Lambda 表示是什么:

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


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


}

我在里面没有发现任何溪流。

59221 次浏览

(这个答案只是众多选择中的一个。仅仅因为 已经有验收标志,并不意味着它是最好的。我建议阅读其他的答案,并根据你所处的情况选择一个。国际海事组织:

  • 因为除了简单之外,它不需要在我的解决方案中进行额外的迭代。
  • 对于 Java9,我会选择 Tagir Valeev 回答中描述的解决方案)

您可以使用 Collections.list将元素从 Enumeration复制到 ArrayList,然后像这样使用它

Collections.list(yourEnumeration).forEach(yourAction);

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

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

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

如果代码中有很多 枚举,我建议创建一个静态帮助器方法,将 枚举转换为 溪流。静态方法可能看起来如下:

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

将该方法与 静态输入静态输入一起使用。与 Holger 的解决方案相反,您可以从不同的 溪流操作中获益,这可能使现有代码更加简单。这里有一个例子:

Map<...> map = enumerationAsStream(enumeration)
.filter(Objects::nonNull)
.collect(groupingBy(...));

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

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

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

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

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

现在您有了一个标准的 Java8流可以以任何方式使用!您可以通过 true进行并行处理。

从枚举转换为 Iterator 使用以下任何一项:

  • 来自 Spring 3.2的 CollectionUtils.toIterator()或者您可以使用
  • 来自 Apache Commons Collections3.2的 IteratorUtils.asIterator()
  • 来自谷歌番石榴的 Iterators.forEnumeration()

自 Java-9以来,新的默认方法 Enumeration.asIterator()将使纯 Java 解决方案更加简单:

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

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

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

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

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