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 s
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())
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.
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);
}
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.