I have a third party library that gives me an Enumeration
. I want to work with that enumeration lazily as a Java 8 Stream
, calling thing
This answer already provides a solution which creates a Stream
out of an Enumeration
:
public static
Stream enumerationAsStream(Enumeration e) { return StreamSupport.stream( Spliterators.spliteratorUnknownSize( new Iterator () { 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.
Still, it has room for improvement. I’d always add a forEachRemaining
method when there is a straight-forward way to process all elements. Said method will be called by the Stream
implementation for most non-short-circuiting operations:
public static Stream enumerationAsStream(Enumeration e) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
new Iterator() {
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. The created Iterator
will get wrapped into an implementation of the new Spliterator
interface and provides no advantage over implementing Spliterator
directly:
public static Stream enumerationAsStream(Enumeration e) {
return StreamSupport.stream(
new Spliterators.AbstractSpliterator(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
. It only requires its readers to learn about the new API.