15

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>?

dimo414
  • 47,227
  • 18
  • 148
  • 244
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 1
    You confused me by saying `new Scanner(System.in); // it's an Iterable` – Holger Aug 31 '15 at 18:59
  • 1
    There is no simpler way but is this really that common that a simpler way is required? – Holger Aug 31 '15 at 19:07
  • @holger because `class Scanner implements Iterator` and yes, I often want to stream the elements of an iterator (not just scanner of course, that's just an example of an Itsrator that isn't a Collection) – Bohemian Aug 31 '15 at 21:45
  • http://stackoverflow.com/a/23177907/829571 – assylias Aug 31 '15 at 22:21
  • 5
    For what it's worth, regarding Scanner, [https://bugs.openjdk.java.net/browse/JDK-8072722](https://bugs.openjdk.java.net/browse/JDK-8072722). – Stuart Marks Aug 31 '15 at 22:44
  • @Bohemian: to me it seems that I can count the examples of `Iterator`s, not being produced by an `Iterable`, with one hand, `Scanner` being the most prominent one (though I even have little use for that class, as, when I use regular expressions, I usually need more control over the operation). As it seems that it will get special treatment in the next Java version anyway, which real-life examples are left then? – Holger Sep 01 '15 at 08:02
  • 3
    possible duplicate of [Java8 Iterator to Stream](http://stackoverflow.com/questions/24511052/java8-iterator-to-stream) – dimo414 Sep 11 '15 at 22:29

1 Answers1

11

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();
Steve K
  • 4,863
  • 2
  • 32
  • 41