如何将 Java 枚举转换为流?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33242577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:30:13  来源:igfitidea点击:

How do I turn a Java Enumeration into a Stream?

javajava-8java-stream

提问by Micah Zoltu

I have a third party library that gives me an Enumeration<String>. I want to work with that enumeration lazily as a Java 8 Stream, calling things like filter, mapand flatMapon it.

我有一个第三方库,它给了我一个Enumeration<String>. 我想懒洋洋地与枚举工作作为Java 8 Stream,呼叫之类的东西filtermapflatMap在其上。

Is there an existing library that has this in it? I am already referencing Guava and Apache Commons so if either of those have the solution that would be ideal.

是否有一个现有的图书馆有这个?我已经在参考 Guava 和 Apache Commons,所以如果其中任何一个都有理想的解决方案。

Alternatively, what is the best/easiest way to turn an Enumerationinto a Streamwhile retaining the lazy nature of everything?

或者,将 anEnumeration变成Streamwhile 保留一切的懒惰性质的最佳/最简单的方法是什么?

采纳答案by Holger

This answeralready provides a solution which creates a Streamout of an Enumeration:

这个答案已经提供了一个解决方案,它创建了Stream一个Enumeration

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

It should be emphasized that the resulting Streamisas lazy as any other Stream, as it won't process any items before the terminal action has been commenced and if the terminal operation is short-circuiting, it will iterate only as many items as necessary.

应当强调的是,由此而来Stream懒任何其他Stream的,因为它不会处理任何物品的终端动作已经开始之前,如果终端操作是短路,它会遍历只有尽可能多的项目是必要的。

Still, it has room for improvement. I'd always add a forEachRemainingmethod when there is a straight-forward way to process all elements. Said method will be called by the Streamimplementation for most non-short-circuiting operations:

尽管如此,它仍有改进的空间。forEachRemaining当有一种直接的方法来处理所有元素时,我总是会添加一个方法。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();
                }
                public void forEachRemaining(Consumer<? super T> action) {
                    while(e.hasMoreElements()) action.accept(e.nextElement());
                }
            },
            Spliterator.ORDERED), false);
}

However, the code above is a victim of the “using Iteratorbecause it's so familiar” antipattern. The created Iteratorwill get wrapped into an implementation of the new Spliteratorinterface and provides no advantage over implementing Spliteratordirectly:

然而,上面的代码是“Iterator因为它太熟悉而使用”反模式的受害者。createdIterator将被包装到新Spliterator接口的实现中,与Spliterator直接实现相比没有任何优势:

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
            public boolean tryAdvance(Consumer<? super T> action) {
                if(e.hasMoreElements()) {
                    action.accept(e.nextElement());
                    return true;
                }
                return false;
            }
            public void forEachRemaining(Consumer<? super T> action) {
                while(e.hasMoreElements()) action.accept(e.nextElement());
            }
    }, false);
}

On the source code level, this implementation is as simple as the Iterator-based, but eliminates the delegation from a Spliteratorto an Iterator. It only requires its readers to learn about the new API.

在源代码级别,此实现与Iterator-based一样简单,但消除了从 aSpliterator到 an的委托Iterator。它只需要读者了解新的 API。

回答by Federico Peralta Schaffner

According to Guava docs, you could use the Iterators.forEnumeration()method:

根据Guava docs,您可以使用该Iterators.forEnumeration()方法:

Enumeration<Something> enumeration = ...;

Iterator<SomeThing> iterator = Iterators.forEnumeration(enumeration);

And in this question, it is explained how to get a stream from an iterator:

这个问题中,解释了如何从迭代器获取流:

Stream<Something> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.ORDERED),
    false);

回答by Stuart Marks

In Java 9 it is possible to convert an Enumerationto a Streamwith a one-liner:

在 Java 9 中,可以使用单行将 an 转换Enumeration为 a Stream

Enumeration<String> en = ... ;
Stream<String> str = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(en.asIterator(), Spliterator.ORDERED),
    false
);

(Well, it's a rather long line.)

(嗯,这是一个相当长的线。)

If you're not on Java 9, you can convert the Enumerationinto an Iteratormanually using the technique given in Holger's answer.

如果您使用的不是 Java 9,则可以使用Holger's answer 中给出的技术手动将其转换Enumeration为。Iterator

回答by Tagir Valeev

In my StreamExlibrary there's simple method StreamEx.of(Enumeration)which does the job:

在我的StreamEx库中,有一个简单的方法StreamEx.of(Enumeration)可以完成这项工作:

Stream<String> stream = StreamEx.of(enumeration);

Note that it not just a shortcut to the @Holger solution, but implemented in different manner. In particular, it has significantly better parallel execution characteristics compared to solutions involving Spliterators.spliteratorUnknownSize().

请注意,它不仅仅是@Holger 解决方案的快捷方式,而是以不同的方式实现的。特别是,与涉及Spliterators.spliteratorUnknownSize().

回答by Brice

Why not using vanilla Java :

为什么不使用香草 Java :

Collections.list(enumeration).stream()...

However as mentionned by @MicahZoltu, the number of items in the enumeration has to be taken into account, as Collections.listwill first iterate over the enumeration to copy the elements in an ArrayList. From there the regular streammethod can be used. While this is usual for many collection stream operations, if the enumeration is too big (like infinite), this can cause problem because the enumeration has to be transformed in a list then the other approaches described here should be used instead.

但是,正如@MicahZoltu 所提到的,必须考虑枚举中的项目数,因为Collections.list将首先迭代枚举以复制ArrayList. 从那里stream可以使用常规方法。虽然这对于许多集合流操作来说很常见,但如果枚举太大(如无限),这可能会导致问题,因为枚举必须在列表中转换,然后应该使用此处描述的其他方法。