我有一个第三方库,它给了我一个 Enumeration<String>
。 我想懒惰地将该枚举作为Java 8 Stream
进行处理,并调用诸如filter
、map
和flatMap
等函数。
是否有现成的库可以实现这个功能?我已经在引用 Guava 和 Apache Commons,如果其中任何一个有解决方案,那就太好了。
另外,将 Enumeration
转换为 Stream
并保留一切的懒惰特性,哪种方法最好/最容易?
我有一个第三方库,它给了我一个 Enumeration<String>
。 我想懒惰地将该枚举作为Java 8 Stream
进行处理,并调用诸如filter
、map
和flatMap
等函数。
是否有现成的库可以实现这个功能?我已经在引用 Guava 和 Apache Commons,如果其中任何一个有解决方案,那就太好了。
另外,将 Enumeration
转换为 Stream
并保留一切的懒惰特性,哪种方法最好/最容易?
为什么不使用标准Java:
Collections.list(enumeration).stream()...
然而,正如@MicahZoltu所提到的那样,枚举中项目的数量必须考虑在内,因为Collections.list
将首先迭代枚举以将元素复制到ArrayList
中。从那里可以使用常规的stream
方法。尽管这对于许多集合流操作来说很常见,但如果枚举太大(例如无限),这可能会导致问题,因为必须将枚举转换为列表,然后应改用此处描述的其他方法。
这个答案已经提供了将 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);
}
应该强调的是,产生的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);
}
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);
}
Iterator
的实现一样简单,但是省略了从 Spliterator
委托到 Iterator
的过程。它只需要读者了解新的 API 即可。Enumeration#asIterator()
方法。 - dan1st在Java 9中,可以使用一行代码将Enumeration
转换为Stream
:
Enumeration<String> en = ... ;
Stream<String> str = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(en.asIterator(), Spliterator.ORDERED),
false
);
(嗯,这是一行相当长的代码。)
如果您不使用Java 9,则可以使用Holger的答案中提供的技术手动将枚举
转换为迭代器
。
根据Guava文档,您可以使用Iterators.forEnumeration()
方法:
Enumeration<Something> enumeration = ...;
Iterator<SomeThing> iterator = Iterators.forEnumeration(enumeration);
而且在这个问题中,解释了如何从迭代器获取流:
Stream<Something> stream = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
iterator, Spliterator.ORDERED),
false);
StreamEx.of(Enumeration)
可以完成该任务:Stream<String> stream = StreamEx.of(enumeration);
Spliterators.spliteratorUnknownSize()
的解决方案相比,它具有明显更好的并行执行特性。
Enumeration
(Java 1.0)转换为Iterator
(Java 1.2)。我正在询问如何将其转换为Stream
(Java 1.8)。虽然似乎链接问题中的最后一个答案回答了这个问题,但该答案对于所提出的问题是错误的。应该在此提供该答案,以便未来的搜索者可以成功找到它。也许@ArneBurmeister想要复制答案到这里,以便直接回答这个问题? - Micah ZoltuStream
的替代方法的合适地方(因为这不是链接问题的范围),所以重新打开此问题。 - Holger