如何将 Java 枚举转换为流?

2022-08-31 11:17:11

我有一个第三方库,它给了我一个.我想像 Java 8 一样懒惰地使用这个枚举,调用类似 的东西,并在它上面。Enumeration<String>StreamfiltermapflatMap

是否有现有的库中包含此内容?我已经引用了Guava和Apache Commons,所以如果其中任何一个有解决方案,那将是理想的。

或者,将一个同时保持一切的懒惰本质的最好/最简单的方法是什么?EnumerationStream


答案 1

为什么不使用vanilla Java:

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

但是,正如@MicahZoltu中提到的,必须考虑枚举中的项数,因为首先将循环访问枚举以复制 .从那里可以使用常规方法。虽然这对于许多收集流操作是常见的,但如果枚举太大(如无限),这可能会导致问题,因为枚举必须在列表中进行转换,那么应该使用此处描述的其他方法。Collections.listArrayListstream


答案 2

这个答案已经提供了一个解决方案,该解决方案可以创建一个:StreamEnumeration

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

应该强调的是,结果与其他任何结果样懒惰,因为它在终端操作开始之前不会处理任何项目,如果终端操作短路,它将仅迭代所需数量的项目。StreamStream

尽管如此,它仍有改进的余地。当有一种直接的方法来处理所有元素时,我总是会添加一个方法。所述方法将由大多数非短路操作的实现调用:forEachRemainingStream

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

但是,上面的代码是“使用,因为它是如此熟悉”的反模式的受害者。创建的将被包装到新接口的实现中,并且与直接实现相比没有任何优势:IteratorIteratorSpliteratorSpliterator

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

在源代码级别,此实现与基于 -一样简单,但消除了从 a 到 .它只需要读者了解新的API。IteratorSpliteratorIterator


推荐