[英]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
,在其上调用filter
, map
和flatMap
的东西。
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
的实现一样简单,但消除了从Spliterator
到Iterator
的委派。 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.