Spliterator in Java
What is a Spliterator?
A Spliterator is a type of object introduced in Java 8 that is used to traverse over elements similar to an Iterator. Spliterators allow you to partition the elements and process them in parallel. A Spliterator iterates over the elements in more of a functional programming way and is used in the Stream API. Spliterators are obtained through a factory method on collections using the spliterator() method.
final var spliterator = collection.spliterator();
Traversing
Iterators use a hasNext() and a next() method for traversing. With a Spliterator, you use a tryAdvance() method that takes a Consumer. This method will return true if there is a next element and false if there isn't one.
final boolean hasNext = spliterator.tryAdvance(
element -> System.out.println(element)
);
You could traverse the whole Spliterator printing each element with the following:
while (spliterator.tryAdvance(System.out::println)) {
}
Regardless of where you are in the Spliterator, you can traverse the rest of the elements using the forEachRemaining() method.
spliterator.forEachRemaining(
element -> System.out.println(element)
);
Size
Spliterators can both have a known size or be an infinite number of elements. You can use the estimateSize() method to get the size of a Spliterator.
final int size = spliterator.estimateSize();
This will return the size if it is known. If it is an infinite number of elements or it is too expensive to compute, this will return Long.MAX_VALUE.
Splitting
Spliterators can be split or partitioned so they can be processed in parallel. This will split it into two parts. This is done using the trySplit() method.
final List<Integer> numbers = Stream.iterate(0, i -> i + 1)
.limit(10)
.toList();
final Spliterator<Integer> spliterator = list.spliterator();
final Spliterator<Integer> split = spliterator.trySplit();
split.forEachRemaining(System.out::println);
spliterator.forEachRemaining(System.out::println);
This first generates a List with numbers from 1 to 10. It then creates a Spliterator using the spliterator() method. Next, it partitions the Spliterator using the trySplit() method. It then loops through both Spliterators printing each value. This example is a single thread, but each Spliterator could be put into two different threads and processed in parallel. The output of this would be the following:
1
2
3
4
5
6
7
8
9
10
If you were to call estimateSize() on the spliterator variable before trySplit() is called, it would return 10. After trySplit(), each Spliterator would return 5.
The trySplit() method may return null if the Spliterator is empty or it cannot be partitioned.
Characteristics
Characteristics are ORed int values. Each characteristic is defined as an int constant on the Spliterator interface. A Spliterator can have one or more of the following characteristics:
- CONCURRENT: Specifies if the source the Spliterator was obtained from can be concurrently modified through adding, removing, or replacing elements while being traversed.
- DISTINCT: Specifies that each element is unique.
- IMMUTABLE: Specifies if the source the Spliterator was obtained from cannot be modified.
- NONNULL: Specifies that no elements are null.
- ORDERED: Specifies that a Spliterator is a prefix order similar to a List.
- SIZED: Specifies if the number of elements is known and can be obtained using the estimateSize() method. This would be for Spliterators that do not have an infinite number of elements.
- SORTED: Specifies that the Spliterator has a Comparable obtained in the getComparator() method. Spliterators that are SORTED are also ORDERED.
- SUBSIZED: Specifies when splitting through trySplit() that the Spliterator will be SIZED as well.
You can check to see if a Spliterator has a characteristic with the hasCharacteristics() method.
final boolean isOrdered =
spliterator.hasCharacteristics(Spliterator.ORDERED);
Primitive Spliterator
Spliterators have implementation specific for primitive values. These are inner interfaces defined on the Spliterator interface and contain the following:
- Spliterator.OfPrimitve
- Spliterator.OfInt
- Spliterator.OfLong
- Spliterator.OfDouble
Conclusion
Spliterators are a type of iterator used in the Stream API. They are a more functional way to traverse elements and can be partitioned and processed in parallel.