如何将Java枚举转换为流?

Mic*_*ltu 56 java java-8 java-stream

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

是否有现有的库?我已经引用了Guava和Apache Commons,所以如果其中任何一个都有理想的解决方案.

或者,是什么把一个最好/最简单的方式Enumeration进入Stream,同时保留所有的懒惰天性?

Bri*_*ice 100

为什么不使用vanilla Java:

Collections.list(enumeration).stream()...
Run Code Online (Sandbox Code Playgroud)

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

  • 这将枚举整个`枚举`,使其成为一个列表,然后给你流访问列表.如果枚举很小,这可能是一种合理的方法.如果枚举非常大,则这可能是昂贵且不必要的操作.如果枚举是无限的,这将使您的应用程序崩溃. (9认同)

Hol*_*ger 41

这个答案已经提供了一个解决方案,可以创建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);
 }
Run Code Online (Sandbox Code Playgroud)

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

不过,它还有改进的余地.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);
}
Run Code Online (Sandbox Code Playgroud)

但是,上面的代码是"使用Iterator因为它太熟悉"模式的受害者.创建的内容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);
}
Run Code Online (Sandbox Code Playgroud)

在源代码级别,这个实现就像Iterator基于-based 一样简单,但是消除了从a Spliterator到a的委托Iterator.它只需要读者了解新的API ...

  • @IcedD​​ante`ORDERED`意味着有一个已定义的遇到顺序,因此它意味着*不允许*流实现基于假定数据是无序的优化。由于对于未知的“枚举”,我们不知道该命令是否具有含义,因此必须假定该命令“可能”具有含义并指定此特征。当调用者知道顺序与特定数据无关时,调用者仍可以在流上调用“ unordered()”,以实现优化。但是,我们最初的前提必须是订单可能很重要。 (2认同)
  • 请注意,从 java 9 开始就有了 `Enumeration#asIterator()`。 (2认同)

Stu*_*rks 26

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

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

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

如果您不使用Java 9,则可以使用Holger答案中给出的技术将其Enumeration转换为Iterator手动.

  • 如果我们使线条足够长,我们几乎可以将所有东西都变成单线; ^) (17认同)

Fed*_*ner 8

根据Guava文档,您可以使用以下Iterators.forEnumeration()方法:

Enumeration<Something> enumeration = ...;

Iterator<SomeThing> iterator = Iterators.forEnumeration(enumeration);
Run Code Online (Sandbox Code Playgroud)

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

Stream<Something> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.ORDERED),
    false);
Run Code Online (Sandbox Code Playgroud)


Tag*_*eev 6

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

Stream<String> stream = StreamEx.of(enumeration);
Run Code Online (Sandbox Code Playgroud)

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