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.
In Java 8, we can use Stream. iterate to create stream values on demand, so called infinite stream.
Iterators, in Java, are used in Collection Framework to retrieve elements one by one. A stream in Java is a pipeline of objects from an array or a collection data source. A sequential stream is one in which the objects are pipelined in a single stream on the same processing system.
Converting Iterable to Stream 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.
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.
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.
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