33

Is it possible to create a Stream from an Iterator, in which the sequence of objects is the same as that generated by calling the iterator's next() method repeatedly? The specific case I am thinking of concerns the use of the iterator returned by TreeSet.descendingIterator(), but I can imagine other circumstances in which an iterator, but not the collection it references, is available.

For example, for a TreeSet<T> tset we can write tset.stream()... and get a stream of the objects in that set, in the set's sort order, but what if we want them in a different order, such as that available through using descendingIterator()? I am imagining something like tset.descendingIterator().stream()... or stream( tset.descendingIterator() )..., though neither of these forms are valid.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
sdenham
  • 525
  • 1
  • 6
  • 12
  • I'm not too familiar with Java 8, which is why I'm commenting instead of answering, but are you looking for Java's [Stream](http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) interface? It sounds like it might fit your needs (for some operations, at least... Doesn't sound like it'd work if you needed it to function in a more iterator-like manner) – awksp May 03 '14 at 03:25
  • @user3580294 The term stream is unfortunately overloaded, but I am referring to the java.util.stream.Stream interface. I will add an example. – sdenham May 03 '14 at 04:17
  • So you wanted to create a `java.util.stream.Stream` from a `java.util.Iterator`? – awksp May 03 '14 at 04:18

4 Answers4

52
static <T> Stream<T> iteratorToFiniteStream(final Iterator<T> iterator) {
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
}

static <T> Stream<T> iteratorToInfiniteStream(final Iterator<T> iterator) {
    return Stream.generate(iterator::next);
}
Karol Król
  • 3,320
  • 1
  • 34
  • 37
  • I agree, and I know it works, but I don't understand [why the lambda can be assigned to the Iterable](http://stackoverflow.com/questions/41841310/explain-how-this-supplier-lambda-can-be-assigned-to-an-iterable) – Brad Jan 25 '17 at 00:20
  • The second solution will lead to an exception in many (most?) use cases. For example: `Iterator iterator = Arrays.asList(0, 1, 2, 3).iterator(); Stream.generate(iterator::next).forEach(e -> System.out.println(e));` prints 0, 1, 2, 3 and then throws a `NoSuchElementException`. The problem is that `iterator.hasNext()` is never called. – jcsahnwaldt Reinstate Monica Nov 18 '17 at 17:26
  • 1
    @JonaChristopherSahnwaldt Cause your 4 elements stream is far away from "Infinity" ;) Don't you think that in second method there is no need to check if iterator "hasNext"? – Karol Król Nov 19 '17 at 22:08
  • @KarolKról No, I don't think so. In many cases, the second method will lead to an exception. The first method is much better, and it also works for "infinite" Iterators (which are very rare, in my experience). – jcsahnwaldt Reinstate Monica Nov 19 '17 at 23:23
36

For the particular example of NavigableSet.descendingIterator(), I think the simplest way is to use NavigableSet.descendingSet() instead.

But given you are probably interested in the more general case, the following seems to work:

import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.TreeSet;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class Streams {
    public static void main(String... args) {
        TreeSet<String> set = new TreeSet<>();
        set.add("C");
        set.add("A");
        set.add("B");

        Iterator<String> iterator = set.descendingIterator();

        int characteristics = Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
        Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, characteristics);

        boolean parallel = false;
        Stream<String> stream = StreamSupport.stream(spliterator, parallel);

        stream.forEach(System.out::println); // prints C, then B, then A
    }
}

In short, you have to create a Spliterator from the Iterator first using one of the static methods in Spliterators. Then you can create a Stream using the static methods in StreamSupport.

I don't have that much experience with creating Spliterators and Streams by hand yet, so I can't really comment on what the characteristics should be or what effect they will have. In this particular simple example, it didn't seem to matter whether I defined the characteristics as above, or whether I set it to 0 (i.e. no characteristics). There is also a method in Spliterators for creating a Spliterator with an initial size estimate - I suppose in this particular example you could use set.size(), but if you want to handle arbitrary Iterators I guess this won't be the case. Again, I'm not quite sure what effect it has on performance.

andersschuller
  • 13,509
  • 2
  • 42
  • 33
  • 1
    Thanks for both the general solution and for bringing NavigableSet to my attention. From the StreamSupport documentation, I see that java.util.function.Supplier provides an interface for feeding data into streams. – sdenham May 04 '14 at 14:26
  • See Karols answer below, which should be the accepted answer – Jochen Sep 30 '16 at 12:30
3

This doesn't create a stream, but Iterator also has a method called forEachRemaining:

someIterator.forEachRemaining(System.out::println);
someIterator.forEachRemaining(s -> s.doSomething());
//etc.

The argument you pass in is a Consumer which is the same thing you pass to Stream::forEach.

Here are the docs for that method. note that you can't continue the "chain" like you can with a stream. But I've still found this helpful the few times I've wanted a Stream from an Iterator.

Bananeweizen
  • 21,797
  • 8
  • 68
  • 88
Jordan Shurmer
  • 946
  • 7
  • 21
1

As it was written by Karol Król for infinite stream you can use this:

Stream.generate(iterator::next)

but you can also use it for finite stream with takeWhile since Java 9

Stream.generate(iterator::next).takeWhile((v) -> iterator.hasNext())
lczapski
  • 4,026
  • 3
  • 16
  • 32