简体   繁体   English

如何将Java枚举转换为流?

[英]How do I turn a Java Enumeration into a Stream?

I have a third party library that gives me an Enumeration<String> . 我有一个第三方库,它给我一个Enumeration<String> I want to work with that enumeration lazily as a Java 8 Stream , calling things like filter , map and flatMap on it. 我希望懒惰地使用该枚举作为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 Enumeration into a Stream while retaining the lazy nature of everything? 或者,在保留所有内容的惰性的同时,将Enumeration转换为Stream的最佳/最简单方法是什么?

Why not using vanilla Java : 为什么不使用vanilla 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.list will first iterate over the enumeration to copy the elements in an ArrayList . 但是,正如@MicahZoltu所提到的,必须考虑枚举中的项目数,因为Collections.list将首先遍历枚举以复制ArrayList的元素。 From there the regular stream method can be used. 从那里可以使用常规stream方法。 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. 虽然这对于许多集合流操作来说是常见的,但如果枚举太大(如无限),这可能会导致问题,因为枚举必须在列表中进行转换,然后应该使用此处描述的其他方法。

This answer already provides a solution which creates a Stream out of an Enumeration : 这个答案已经提供了一个解决方案,它可以从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); } 

It should be emphasized that the resulting Stream is as 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 forEachRemaining method when there is a straight-forward way to process all elements. 当有一种直接处理所有元素的方法时,我总是会添加一个forEachRemaining方法。 Said method will be called by the Stream implementation for most non-short-circuiting operations: 对于大多数非短路操作, 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 Iterator because it's so familiar” antipattern. 但是,上面的代码是“使用Iterator因为它是如此熟悉的”反模式的受害者。 The created Iterator will get wrapped into an implementation of the new Spliterator interface and provides no advantage over implementing Spliterator directly: 创建的Iterator将被包装到新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 Spliterator to an Iterator . 在源代码级别,此实现与基于Iterator的实现一样简单,但消除了从SpliteratorIterator的委派。 It only requires its readers to learn about the new API. 它只需要读者了解新的API。

In Java 9 it is possible to convert an Enumeration to a Stream with a one-liner: 在Java 9中,可以使用单行将Enumeration转换为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 Enumeration into an Iterator manually using the technique given in Holger's answer . 如果您不使用Java 9,则可以使用Holger答案中给出的技术手动将Enumeration转换为Iterator

According to Guava docs , you could use the Iterators.forEnumeration() method: 根据Guava文档 ,您可以使用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);

In my StreamEx library 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. 请注意,它不仅是@Holger解决方案的快捷方式,而且以不同的方式实现。 In particular, it has significantly better parallel execution characteristics compared to solutions involving Spliterators.spliteratorUnknownSize() . 特别是,与涉及Spliterators.spliteratorUnknownSize()解决方案相比,它具有明显更好的并行执行特性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM