【问题标题】:Iterate an Enumeration in Java 8在 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 中的迭代器取代。不幸的是,您仍然必须使用它。 :|
  • 您可以将您的枚举调整为迭代器:stackoverflow.com/questions/5007082/…
  • @PeterLawrey 迭代器出现了,但仍然有使用枚举的核心 API。泛型出现了,但仍然有使用裸类型或返回 Object 的核心 API。 Lambdas 出现了,但是 Swing 仍然充满了多方法接口,所以我们不能使用它们。当我发现 Java 忘记现代化的 API 时,我真的不再感到惊讶了。这让我很难过。
  • @Trejkaz 是的,Swing 仍然使用 Vector 和 Hashtable。
  • @PeterLawrey Servlet API 仍然使用枚举。

标签: java lambda iteration enumeration java-8


【解决方案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();
                }
            };
        }
        

        【讨论】:

          猜你喜欢
          • 2012-06-08
          • 1970-01-01
          • 2010-11-09
          • 2011-02-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-12
          • 1970-01-01
          相关资源
          最近更新 更多