在 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:

对于 Java 8 Holger's answer 是最好的,因为除了简单之外,它不需要在我的解决方案中发生的额外迭代。 对于 Java 9,我会选择 Tagir Valeev answer) 中描述的解决方案

您可以使用Collections.listEnumeration 中的元素复制到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 &lt;T&gt; Stream&lt;T&gt; enumerationAsStream(Enumeration&lt;T&gt; 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)

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

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

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 中迭代枚举的主要内容,如果未能解决你的问题,请参考以下文章

Java重温学习笔记,迭代枚举元素

如何迭代Java中的枚举字段? [复制]

枚举器和迭代器

Java枚举可以迭代吗? [复制]

如何在java中遍历枚举[重复]

Java 枚举