Say you want to stream the elements of an iterator; let's use a concrete example of a Scanner
, which implements Iterator<String>
.
Given an Iterator
, say:
// Scanner implements Iterator<String>
Iterator<String> scanner = new Scanner(System.in);
Options to create a Stream<String>
from it are the clunky:
StreamSupport.stream(
Spliterators.spliteratorUnknownSize(scanner, Spliterator.ORDERED), false);
or the slightly more terse, but obtuse:
StreamSupport.stream(
((Iterable<String>) () -> new Scanner(System.in)).spliterator(), false);
Is there a factory method somewhere in the JDK that returns a Stream<T>
given an Iterator<T>
?
To iterate, hasNext() and next() methods are used in a loop. Classes that implement the Iterable interface need to override the iterator() method. Classes that implement Iterator interface need to override hasNext(), next() and remove() methods.
The Iterable interface is designed keeping generality in mind and does not provide any stream() method on its own. Simply put, you can pass it to StreamSupport. stream() method and get a Stream from the given Iterable instance.
I would simply use Stream.generate(iterator::next)
. Yes, it is an infinite stream, but so is the scanner from System.in
, unless you know how many lines you're asking for in which case it's easy enough to use
Stream.generate(iterator::next).limit(numLines);
This prevents the iterator from having to be iterated twice (once as the iterator, once as the stream).
If you need a sized stream without knowing how big it will be, but don't want to clutter your code just create a utility method that explicitly takes an Iterable<T>
:
public static <T> Stream<T> stream(Iterable<T> it){
return StreamSupport.stream(it.spliterator(), false);
}
It ends up being more legible than trying to cram it all on one line, and
then you can just call stream(()->iterator);
or stream(()->new Scanner(System.in));
You can add the second convenience method easily enough, too:
public static <T> Stream<T> stream(Iterator<T> it){
return stream(()->it);
}
enabling you to call stream(iterator);
or stream(new Scanner(System.in));
Although, if I were going to read System.in
into a stream, I'd probably use a Reader rather than a Scanner anyway:
return new BufferedReader(new InputStreamReader(System.in)).lines();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With