在 Java 8 中迭代枚举
Posted
技术标签:
【中文标题】在 Java 8 中迭代枚举【英文标题】:Iterate an Enumeration in Java 8 【发布时间】:2014-06-09 07:40:03 【问题描述】:是否可以使用 Lambda 表达式迭代 Enumeration
?以下代码 sn-p 的 Lambda 表示形式是什么:
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
while (nets.hasMoreElements())
NetworkInterface networkInterface = nets.nextElement();
我没有在其中找到任何流。
【问题讨论】:
枚举在 1998 年被 Java 1.2 中的迭代器取代。不幸的是,您仍然必须使用它。 :| 您可以将您的枚举调整为迭代器:***.com/questions/5007082/… @PeterLawrey 迭代器出现了,但仍然有使用枚举的核心 API。泛型出现了,但仍然有使用裸类型或返回 Object 的核心 API。 Lambdas 出现了,但是 Swing 仍然充满了多方法接口,所以我们不能使用它们。当我发现 Java 忘记现代化的 API 时,我真的不再感到惊讶了。这让我很难过。 @Trejkaz 是的,Swing 仍然使用 Vector 和 Hashtable。 @PeterLawrey Servlet API 仍然使用枚举。 【参考方案1】:(这个答案显示了许多选项之一。仅仅因为 has 有接受标记,并不意味着它是最好的。我建议阅读其他答案并根据具体情况选择一个你所处的情况。IMO:
您可以使用Collections.list
将Enumeration
中的元素复制到ArrayList
,然后像这样使用它
Collections.list(yourEnumeration).forEach(yourAction);
【讨论】:
问题是现在您必须将所有元素存储在一个列表中。如果它很小,可能没问题。但值得一提的是,有时它会太大而无法放入内存。 java.util.stream.Stream#of(yourEnumeration.values()).forEach() 怎么样? @Filip 你的评论是关于Enum
,但问题是关于Enumeration
。【参考方案2】:
如果您的代码中有很多 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);
使用带有静态导入的方法。与 Holger 的解决方案相比,您可以从不同的 stream 操作中受益,这可能会使现有代码更加简单。这是一个例子:
Map<...> map = enumerationAsStream(enumeration)
.filter(Objects::nonNull)
.collect(groupingBy(...));
【讨论】:
我认为两者是互补的,就像list.forEach(…)
和list.stream(). ⟨stream ops⟩ .forEach(…)
。
这怎么不是 JDK 的一部分?
public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) return Collections.list(e).stream();
会做同样的事情,但要简单得多。
@ThomasFritsch 的提议制作了列表的中间副本,这是要避免的。【参考方案3】:
从 Java-9 开始,将会有新的默认方法 Enumeration.asIterator()
,这将使纯 Java 解决方案更简单:
nets.asIterator().forEachRemaining(iface -> ... );
【讨论】:
【参考方案4】:如果您不喜欢 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
功能)...
【讨论】:
【参考方案5】:您可以使用以下标准函数的组合:
StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel)
您还可以添加更多特征,例如 NONNULL
或 DISTINCT
。
应用静态导入后,这将变得更具可读性:
stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)
现在您有了一个可以以任何方式使用的标准 Java 8 Stream!您可以通过true
进行并行处理。
要从枚举转换为迭代器,请使用以下任何一种:
CollectionUtils.toIterator()
来自 Spring 3.2 或者您可以使用
IteratorUtils.asIterator()
来自 Apache Commons Collections 3.2
Iterators.forEnumeration()
来自 Google Guava
【讨论】:
CollectionUtils 从何而来? JDK中好像没有。 @Martin,好像是org.apache.commons.collections.CollectionUtils
。
@Vadzim 我检查了Apache Commons Collections 1.0、2.0、2.1.1、3.2.1 和 4.0,但没有一个名为 CollectionUtils 的类包含名为 toIterator 的方法。
对不起,很困惑,从 Spring 3.2 得到的【参考方案6】:
对于 Java 8,枚举到流的最简单转换是:
Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
【讨论】:
【参考方案7】:我知道这是一个老问题,但我想提出一个 Collections.asList 和 Stream 功能的替代方案。由于问题的标题是“迭代枚举”,我认识到有时您想使用 lambda 表达式,但增强的 for 循环可能更可取,因为枚举对象可能会引发异常,并且 for 循环更容易封装在更大的 try-捕获代码段(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();
;
【讨论】:
以上是关于在 Java 8 中迭代枚举的主要内容,如果未能解决你的问题,请参考以下文章