Since Java 8, Spliterators are a special type of iterator that supports parallel iteration of portions of the source such as an Array, Set, List, or IO channel. Although Spliterators mainly support parallel programming, we can use Spliterator even if we won’t be using parallel execution.
The ArrayList.spliterator() returns the instance of Spliterator that is last-binding and fail-fast.
- Late binding means it binds to the data source at the point of first traversal or first split, rather than at the time of the Spliterator creation.
- Fail-fast means that it throws a ConcurrentModificationException if it detects that the data source has been structurally modified after it was created. Structural changes include adding, removing, or updating elements, which can compromise the consistency of the data being traversed.
// Get the Spliterator from the ArrayList
Spliterator<Integer> spliterator = arraylist.spliterator();
// Convert Spliterator to parallel Stream and process elements in parallel
StreamSupport.stream(spliterator, true).forEach(System.out::println);
1. ArrayList spliterator() Method
In the case of ArrayList, the spliterator() method returns the instance of the ArrayListSpliterator class which is in an inner class of ArrayList and implements Spliterator interface.
public Spliterator<E> spliterator() {
return new ArrayListSpliterator<>(this, 0, -1, 0);
}
static final class ArrayListSpliterator<E> implements Spliterator<E> {
//implementation
}
The spliterator returned by ArrayList is :
- ORDERED – indicates that the elements have a defined order when traversing and partitioning.
- SORTED – means that the elements follow a predefined sort order.
- SUBSIZED – indicates that this and any further resulting Spliterator are SIZED. Here SIZED means the Spliterator has been created from a source with a known size.
2. ArrayList spliterator() Example
A Spliterator
can be used for many usecases. A few are usecases are discussed in below given examples.
2.1. The tryAdvance(): Iterate one element at a time
Java program to iterate one element at a time using a spliterator. It is equivalent to iterator.next() method from Iterator interface.
ArrayList<Integer> digits = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));
Spliterator<Integer> sItr = digits.spliterator();
sItr.tryAdvance( d -> System.out.println( d ) );
sItr.tryAdvance( d -> System.out.println( d ) );
sItr.tryAdvance( d -> System.out.println( d ) );
Program output.
1
2
3
2.2. The forEachRemaining(): Iterate all elements
Java program to iterate all elements and perform an action on them. It is equivalent to iterator.hasNext() method along with iterator.next() in a loop.
ArrayList<Integer> digits = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));
Spliterator<Integer> sItr = digits.spliterator();
sItr.tryAdvance( d -> System.out.println( d ) ); //1
sItr.tryAdvance( d -> System.out.println( d ) ); //2
sItr.forEachRemaining( d -> System.out.println( d ) ); //3,4,5,6
Program output.
1
2
3
4
5
6
2.3. The trySplit(): Parallel Processing
If you are working on a concurrent application and the list has a large number of elements then it’s a good idea to divide the list into two parts and process parallelly.
The trySplit()
method splits the current spliterator into two and returns the new one. The elements it is pointing to are divided into two equal lists.
Keep in mind that the individual
Spliterator
is not thread safe, by default. It is responsibility of application code to create different threads and hand over theSpliterator
instances.
ArrayList<Integer> digits = new ArrayList<>(Arrays.asList(1,2,3,4,5,6));
Spliterator<Integer> sItr1 = digits.spliterator();
Spliterator<Integer> sItr2 = sItr1.trySplit();
System.out.println(sItr1.getExactSizeIfKnown()); //3
sItr1.forEachRemaining( d -> System.out.println( d ) ); //4,5,6
System.out.println("===========");
System.out.println(sItr2.getExactSizeIfKnown()); //3
sItr2.forEachRemaining( d -> System.out.println( d ) ); //1,2,3
Program output.
3
4
5
6
===========
3
1
2
3
2.4. Batch Processing
The Spliterator
can be used for bulk processing operations, such as applying a batch operation to a subset of elements.
import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
public class BatchProcessingExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("One");
list.add("Two");
list.add("Three");
list.add("Four");
Spliterator<String> spliterator = list.spliterator();
int batchSize = 2;
List<String> batch = new ArrayList<>(batchSize);
while (spliterator.tryAdvance(batch::add)) {
if (batch.size() == batchSize) {
processBatch(batch);
batch.clear();
}
}
if (!batch.isEmpty()) {
processBatch(batch);
}
}
private static void processBatch(List<String> batch) {
System.out.println("Processing batch: " + batch);
}
}
2.5. Splitting Workload for Recursive Algorithms
The Spliterator
can be split and used in recursive algorithms, such as implementing a parallel version of a divide-and-conquer algorithm.
import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
public class RecursiveSplittingExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 16; i++) {
list.add(i);
}
Spliterator<Integer> spliterator = list.spliterator();
parallelSum(spliterator);
}
private static void parallelSum(Spliterator<Integer> spliterator) {
long size = spliterator.estimateSize();
if (size <= 4) { // Base case for the recursive splitting
spliterator.forEachRemaining(element -> System.out.println(Thread.currentThread().getName() + " - " + element));
return;
}
Spliterator<Integer> split = spliterator.trySplit();
if (split != null) {
Thread leftThread = new Thread(() -> parallelSum(spliterator));
Thread rightThread = new Thread(() -> parallelSum(split));
leftThread.start();
rightThread.start();
try {
leftThread.join();
rightThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
3. Difference between Iterator and Spliterator
Iterator | Spliterator |
---|---|
Since Java 1.2. | Since Java 8. |
Can be used to iterate all collection classes. | Can be used to iterate array, stream, list and set. Not possible with map. |
Does not support parallel processing. | Supports parallel processing. |
That’s all for the ArrayList spliterator() method in Java.
Happy Learning !!
Read More:
A Guide to Java ArrayList
ArrayList Java Docs
Spliterator Java Docs
Comments