How to convert an Iterator to a Stream?

JavaIteratorJava 8

Java Problem Overview


I am looking for a concise way to convert an Iterator to a Stream or more specifically to "view" the iterator as a stream.

For performance reason, I would like to avoid a copy of the iterator in a new list:

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Collection<String> copyList = new ArrayList<String>();
sourceIterator.forEachRemaining(copyList::add);
Stream<String> targetStream = copyList.stream();

Based on the some suggestions in the comments, I have also tried to use Stream.generate:

public static void main(String[] args) throws Exception {
    Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
    Stream<String> targetStream = Stream.generate(sourceIterator::next);
    targetStream.forEach(System.out::println);
}

However, I get a NoSuchElementException (since there is no invocation of hasNext)

Exception in thread "main" java.util.NoSuchElementException
    at java.util.AbstractList$Itr.next(AbstractList.java:364)
    at Main$$Lambda$1/1175962212.get(Unknown Source)
    at java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.java:1351)
    at java.util.Spliterator.forEachRemaining(Spliterator.java:326)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at Main.main(Main.java:20)

I have looked at StreamSupport and Collections but I didn't find anything.

Java Solutions


Solution 1 - Java

One way is to create a Spliterator from the Iterator and use that as a basis for your stream:

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = StreamSupport.stream(
          Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED),
          false);

An alternative which is maybe more readable is to use an Iterable - and creating an Iterable from an Iterator is very easy with lambdas because Iterable is a functional interface:

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();

Iterable<String> iterable = () -> sourceIterator;
Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);

Solution 2 - Java

Since version 21, Guava library provides Streams.stream(iterator)

It does what @assylias's answer shows.

Solution 3 - Java

Great suggestion! Here's my reusable take on it:

public class StreamUtils {

    public static <T> Stream<T> asStream(Iterator<T> sourceIterator) {
        return asStream(sourceIterator, false);
    }

    public static <T> Stream<T> asStream(Iterator<T> sourceIterator, boolean parallel) {
        Iterable<T> iterable = () -> sourceIterator;
        return StreamSupport.stream(iterable.spliterator(), parallel);
    }
}
  

And usage (make sure to statically import asStream):

List<String> aPrefixedStrings = asStream(sourceIterator)
                .filter(t -> t.startsWith("A"))
                .collect(toList());

Solution 4 - Java

This is possible in Java 9.

Stream.generate(() -> null)
    .takeWhile(x -> iterator.hasNext())
    .map(n -> iterator.next())
    .forEach(System.out::println);

Solution 5 - Java

Create Spliterator from Iterator using Spliterators class contains more than one function for creating spliterator, for example here am using spliteratorUnknownSize which is getting iterator as parameter, then create Stream using StreamSupport

Spliterator<Model> spliterator = Spliterators.spliteratorUnknownSize(
		iterator, Spliterator.NONNULL);
Stream<Model> stream = StreamSupport.stream(spliterator, false);

Solution 6 - Java

import com.google.common.collect.Streams;

and use Streams.stream(iterator) :

Streams.stream(iterator)
       .map(v-> function(v))
       .collect(Collectors.toList());

Solution 7 - Java

Another way to do this on Java 9+ using Stream::iterate(T, Predicate, UnaryOperator):

Stream.iterate(iterator, Iterator::hasNext, UnaryOperator.identity())
        .map(Iterator::next)
        .forEach(System.out::println);

Solution 8 - Java

1 assylias's solution wrapped in a method:

public static <T> Stream<T> toStream(Iterator<T> iterator) {
    return StreamSupport.stream(((Iterable<T>)() -> iterator).spliterator(), false);
}

2 guava Streams implementation (marked with @Beta):

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

Solution 9 - Java

Use Collections.list(iterator).stream()...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongontardView Question on Stackoverflow
Solution 1 - JavaassyliasView Answer on Stackoverflow
Solution 2 - Javanuméro6View Answer on Stackoverflow
Solution 3 - JavaMatanView Answer on Stackoverflow
Solution 4 - JavaPhilipRomanView Answer on Stackoverflow
Solution 5 - JavaBassem Reda ZohdyView Answer on Stackoverflow
Solution 6 - JavasnehaView Answer on Stackoverflow
Solution 7 - Javaaksh1618View Answer on Stackoverflow
Solution 8 - JavaMarinos AnView Answer on Stackoverflow
Solution 9 - JavaIsrael C. S. RochaView Answer on Stackoverflow