Create a Sequential Stream from an Iterator in Java
This post will discuss how to create a sequential stream from an iterator in Java.
A sequential stream is a stream that processes elements one by one in a single thread. An iterator is an object that allows traversing through a collection of elements. Here are some of the methods to create a sequential stream from an iterator:
1. Using a Spliterator
Creating a sequential stream from an iterator is a two-step process in Java. The first step involves converting the iterator into a spliterator, and in the second step, we turn that spliterator into a Stream. A spliterator can split a source of elements into smaller parts and traverse them. To create a spliterator from an iterator, we can use the Spliterators.spliteratorUnknownSize() method, which takes an iterator and some characteristics as parameters. Then, we can call the StreamSupport.stream() method to create a new sequential or parallel stream. It takes a spliterator and a boolean flag indicating whether the stream is parallel or not, and returns a stream. Here’s an example of this approach:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import java.util.Arrays; import java.util.Iterator; import java.util.Spliterator; import java.util.Spliterators; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; class Main { public static <T> Stream<T> iteratorToStream(Iterator<T> iterator) { // Characteristics of this spliterator's elements int characteristics = Spliterator.ORDERED | Spliterator.NONNULL; // convert the iterator into a Spliterator Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize( iterator, characteristics); // flag to make the resulting stream run sequentially or in parallel boolean parallel = false; // turn spliterator into an ordered, sequential stream return StreamSupport.stream(spliterator, parallel); } public static void main(String[] args) { Iterator<String> iterator = Arrays.asList("A", "B", "C", "D").iterator(); Stream<String> stream = iteratorToStream(iterator); stream.forEach(System.out::println); // A, B, C, D } } |
2. Using an Iterable
The Iterable interface provides a spliterator() method that creates a spliterator over the elements described by the iterable. Since Iterable interface declares a single abstract method iterator() that returns an Iterator<T>, this makes iterable effectively a FunctionalInterface and creating an iterable from an iterator can be done using a lambda expression that returns the iterator itself. To illustrate, consider the following example.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import java.util.Arrays; import java.util.Iterator; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; class Main { public static <T> Stream<T> iteratorToStream(Iterator<T> iterator) { // get an Iterable from an Iterator Iterable<T> iterable = () -> iterator; // flag to make the resulting stream run sequentially or in parallel boolean parallel = false; // get Spliterator from Iterable and turn it into a sequential stream return StreamSupport.stream(iterable.spliterator(), parallel); } public static void main(String[] args) { Iterator<String> iterator = Arrays.asList("A", "B", "C", "D").iterator(); Stream<String> stream = iteratorToStream(iterator); stream.forEach(System.out::println); // A, B, C, D } } |
Please note that the Iterable.spliterator() method itself internally calls the Spliterators.spliteratorUnknownSize() method to get a spliterator over the elements described by the iterable.
3. Using Guava Library
Guava library introduced Streams class in version 21.0, which has a stream() method that returns a sequential stream of the remaining contents of the iterator. This method also internally calls the Spliterators.spliteratorUnknownSize() method to convert the iterator to a spliterator and StreamSupport.stream() to get a sequential stream from spliterator.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import com.google.common.collect.Streams; import java.util.Arrays; import java.util.Iterator; import java.util.stream.Collectors; import java.util.stream.Stream; class Main { public static void main(String[] args) { Iterator<String> iterator = Arrays.asList("A", "B", "C", "D").iterator(); Stream<String> stream = Streams.stream(iterator); stream.forEach(System.out::println); // A, B, C, D } } |
4. Using Stream.generate() method
Another option is to use the Stream.generate() method with Iterator.next() method as the supplier. But this will only work with infinite streams and throw NoSuchElementException with finite Streams. This is because Iterator.hasNext() is never called to determine whether the iteration has more elements.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.Iterator; import java.util.stream.IntStream; import java.util.stream.Stream; class Main { public static void main(String[] args) { // create an infinite stream of integers Iterator<Integer> iterator = IntStream.iterate(0, i -> i + 1).iterator(); Stream<Integer> stream = Stream.generate(iterator::next); stream.forEach(System.out::println); // 1, 2, 3, 4, 5, … } } |
If we know the total number of elements in the stream in advance, we can also use this method with finite streams. This way we can limit the stream using the limit() method, as follows:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.stream.Stream; class Main { public static void main(String[] args) { List<String> list = Arrays.asList("A", "B", "C", "D"); Iterator<String> iterator = list.iterator(); Stream<String> stream = Stream.generate(iterator::next).limit(list.size()); stream.forEach(System.out::println); // A, B, C, D } } |
Please note that after getting a stream of the elements from an iterator, the stream should be consumed immediately. Since streams are lazy in Java, it is linked only to an iterator, but if the iterator is used before calling a terminal operation on the stream, the stream would be left with only remaining items.
That’s all about creating a sequential Stream from an iterator in Java.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)