Java Spliterator is another type of Iterator interface to navigate through individual elements. As the name suggests, it supports Split and iteration together. This means we can perform parallel programming using Spliterator.
Table of Contents
Java Spliterator
Spliterator was available from Java8 onwards. We can use it to iterate over both Collections and Stream API apart from Map implementation. Using Java Spliterator, we can split the list and then iterate to retrieve each element. We can also perform a sequential iteration similar to Iterator. It has 1 single method that performs the combined operation of the hasNext()
and next()
methods of the Iterator interface.
The main usage of Java Spliterator is to split the input into different parts and then process each part separately in parallel. It is useful to process large amounts of data through parallel programming.
Java Spliterator methods
Below are the commonly used methods in the Java Spliterator interface:
Methods | Description | Parameter |
---|---|---|
int characteristics() | Returns the characteristics of the spliterator and its elements. | |
long estimateSize() | Returns the estimate of the number of elements that will be encountered by the forEachRemaining traversal | |
void forEachRemaining(Consumer action) | Performs the given action for each element | action - action to be performed |
Comparator getComparator() | If the source is SORTED by a comparator, then it returns the comparator, if sorted in natural order returns null, else it throws IllegalStateException | |
long getExactSizeIfKnown() | Returns the exact size if source is SIZED, else returns by default value -1 | |
boolean hasCharacteristics(int characteristics) | Returns true if the spliterator contains all the characteristics | characteristics - the characteristics that has to be checked |
boolean tryAdvance(Consumer action) | If remaining element exists, it performs the action on it and returns true else it returns false. | action - action to be performed |
Spliterator trysplit() | If the spliterator can be partitioned, returns the spliterator covering the elements else returns null if it cannot be split |
Exceptions in Java Spliterator
Java Spliterator can throw the below exceptions while using its methods:
- NullPointerException – If the action is null in the
forEachRemaining
method andtryAdvance
method. - IllegalStateException – If the spliterator does not report a characteristic of SORTED
Example: Characteristics and hasCharacteristics
Characteristics()
method returns a set of characteristics of the java spliterator and its elements. It may be one of the below 8 static final integer values:
- ORDERED – This denotes that the spliterator elements are defined in an order
- DISTINCT – This means each value is distinct to each other even if we create a spliterator from the set.
- IMMUTABLE – This means we can modify the source of the elements.
- NONNULL – The spliterator element cannot be null.
- SIZED – The value returned by
estimateSize()
represents a finite size. - SORTED – The elements are in a sorted order
- SUBSIZED – This means all spliterator returned by
trySplit()
will be SIZED or SUBSIZED. - CONCURRENT – This denotes that we can modify the source concurrently which means we can add, remove elements concurrently using multiple threads.
hasCharacteristics()
method checks if the spliterator has all the above characteristics. If it contains all the characteristics, it returns true else it returns false.
Below is an example to demonstrate the above two methods of the spliterator. The first output is true since the spliterator has all the characteristics. We have then initialized a variable with spliterator characteristics. Hence it will print the statements where the conditions matches these defined values. That is the reason it prints SIZED and ORDERED and does not print IMMUTABLE.
import java.util.ArrayList; import java.util.Spliterator; public class SplitIteratorExample { public static void main(String[] args) { ArrayList<String> cars = new ArrayList<String>(); cars.add("Maruthi"); cars.add("BMW"); cars.add("Benz"); cars.add("Creta"); cars.add("Nissan"); Spliterator<String> s = cars.spliterator(); int values = Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SIZED; System.out.println("Output of hasCharacteristics: " + s.hasCharacteristics(s.characteristics())); if(s.hasCharacteristics(Spliterator.ORDERED)) System.out.println("Characteristic is Ordered"); if(s.hasCharacteristics(Spliterator.SIZED)) System.out.println("Characteristic is Sized"); if(s.hasCharacteristics(Spliterator.IMMUTABLE)) System.out.println("Characteristic is Immutable"); } }
Output of hasCharacteristics: true Characteristic is Ordered Characteristic is Sized
Example: estimateSize and getExactSizeIfKnown
estimateSize()
method returns the size of the elements in the java spliterator. getExactSizeIfKnown()
method returns the size if present else it returns -1.
import java.util.ArrayList; import java.util.Spliterator; public class SplitIteratorExample { public static void main(String[] args) { ArrayList<String> cars = new ArrayList<String>(); cars.add("Maruthi"); cars.add("BMW"); cars.add("Benz"); cars.add("Creta"); cars.add("Nissan"); Spliterator<String> s = cars.spliterator(); System.out.println("Estimated size: " + s.estimateSize()); System.out.println("getExactSizeIfKnown: " + s.getExactSizeIfKnown()); } }
Estimated size: 5 getExactSizeIfKnown: 5
Example: forEachRemaining
The forEachRemaining()
method performs the specified action for every element in the java spliterator. This method is equivalent to the hasNext()
and the next()
method in the Iterator.
In the below example, the forEachRemaining()
method performs the print action for each element in the spliterator. In other words, it prints each and every element present in the spliterator.
import java.util.ArrayList; import java.util.Spliterator; public class SplitIteratorExample { public static void main(String[] args) { ArrayList<String> cars = new ArrayList<String>(); cars.add("Maruthi"); cars.add("BMW"); cars.add("Benz"); cars.add("Creta"); cars.add("Nissan"); Spliterator<String> s = cars.spliterator(); s.forEachRemaining(System.out::println); } }
Maruthi BMW Benz Creta Nissan
Example: tryAdvance
tryAdvance()
is another method in the Java spliterator that performs the action on the next element in the iteration. It combines the operation of hasNext()
and next()
in the Iterator interface. This method has a parameter action of the Consumer interface. The Consumer interface has an abstract accept
method. Hence we use the lambda operation to implement this action.
In the below example, the action “print” is performed for every element in the spliterator. Since we have given this method within while loop, it prints all the elements in the spliterator.
import java.util.ArrayList; import java.util.Spliterator; public class SplitIteratorExample { public static void main(String[] args) { ArrayList<String> cars = new ArrayList<String>(); cars.add("Maruthi"); cars.add("BMW"); cars.add("Benz"); cars.add("Creta"); cars.add("Nissan"); Spliterator<String> s = cars.spliterator(); while(s.tryAdvance((n) -> System.out.println(n))); } }
Maruthi BMW Benz Creta Nissan
We can also print individual values of the spliterator based on our requirement as in the below example. Here we are printing only the first 2 values.
import java.util.ArrayList; import java.util.Spliterator; public class SplitIteratorExample { public static void main(String[] args) { ArrayList<String> cars = new ArrayList<String>(); cars.add("Maruthi"); cars.add("BMW"); cars.add("Benz"); cars.add("Creta"); cars.add("Nissan"); Spliterator<String> s = cars.spliterator(); s.tryAdvance(a -> System.out.println("First Value: " + a)); s.tryAdvance(a -> System.out.println("Second value: " + a)); } }
First Value: Maruthi Second value: BMW
Example: trySplit
We can use the trySplit()
method to split the spliterator into equal parts and then process them. We mainly use this to process a large amount of data in parallel. This is the main method of the Java spliterator that supports parallel processing.
In the below example, we use the trysplit()
method to split the spliterator. Now the spliterator contains 2 parts, the first of length 3 and the second of length 2. Using forEachRemaining()
method, we can print each element of both the split elements.
import java.util.ArrayList; import java.util.Spliterator; public class SpliteratorDemo { public static void main(String[] args) { ArrayList<String> cars = new ArrayList<String>(); cars.add("Maruthi"); cars.add("BMW"); cars.add("Benz"); cars.add("Creta"); cars.add("Nissan"); Spliterator<String> s1 = cars.spliterator(); Spliterator<String> s2 = s1.trySplit(); System.out.println("Number of elements in SplitList1: " + s1.getExactSizeIfKnown()); System.out.println("Values in SplitList1: "); s1.forEachRemaining(System.out::println); System.out.println("*****************"); System.out.println("Number of elements in SplitList2: " + s2.getExactSizeIfKnown()); System.out.println("Values in SplitList2: "); s2.forEachRemaining(System.out::println); } }
Number of elements in SplitList1: 3 Values in SplitList1: Benz Creta Nissan ***************** Number of elements in SplitList2: 2 Values in SplitList2: Maruthi BMW
Advantages of Java Spliterator
- It supports parallel processing of iteration
- It provides better performance
Difference between Iterator and Spliterator
Below are the differences between Java Iterator and Java spliterator.
Iterator | Spliterator |
---|---|
Available from JDK 1.2 | Available from JDK 1.8 |
It is a universal iterator | It is not a universal iterator |
It does not support parallel processing | It supports parallel processing |
It can be used as iterator for whole Collection API | It can be used as iterator for Collection and Stream API except Map implementation classes. |