Spliterators: How a Stream Splits
What parallel() actually does, and why the source decides whether you get a speed-up.
Open this lesson in the learning hubKey points
- Every stream sits on a
Spliterator: it walks elements one at a time, or hands half away. trySplit()is the whole game. An array orArrayListsplits in O(1) by halving an index range.- A
LinkedListreports the same flags, but its split walks the chain and copies, so parallel rarely pays. - Characteristics such as SIZED, ORDERED and DISTINCT let the pipeline skip work it can prove is pointless.
StreamSupport.stream(spliterator, parallel)turns any Iterable or custom source into a real stream.
Example
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
List<Integer> data = new ArrayList<>(IntStream.rangeClosed(1, 8).boxed().toList());
Spliterator<Integer> sp = data.spliterator();
System.out.println("estimateSize : " + sp.estimateSize());
// trySplit hands half the work away. An ArrayList just halves its index range.
Spliterator<Integer> firstHalf = sp.trySplit();
List<Integer> left = new ArrayList<>();
List<Integer> right = new ArrayList<>();
firstHalf.forEachRemaining(left::add);
sp.forEachRemaining(right::add);
System.out.println("left half : " + left);
System.out.println("right half : " + right);
// The flags look the same for a LinkedList, but its trySplit has to walk and copy.
System.out.println("ArrayList : " + describe(new ArrayList<>(List.of(1, 2, 3, 4)).spliterator()));
System.out.println("LinkedList : " + describe(new LinkedList<>(List.of(1, 2, 3, 4)).spliterator()));
System.out.println("HashSet : " + describe(new HashSet<>(List.of(1, 2, 3, 4)).spliterator()));
// Any Iterable becomes a real stream through its spliterator.
Iterable<String> it = List.of("ada", "grace");
System.out.println("StreamSupport: "
+ StreamSupport.stream(it.spliterator(), false).map(String::toUpperCase).toList());
}
static String describe(Spliterator<?> s) {
StringJoiner j = new StringJoiner(", ");
if (s.hasCharacteristics(Spliterator.SIZED)) { j.add("SIZED"); }
if (s.hasCharacteristics(Spliterator.ORDERED)) { j.add("ORDERED"); }
if (s.hasCharacteristics(Spliterator.DISTINCT)) { j.add("DISTINCT"); }
if (s.hasCharacteristics(Spliterator.SUBSIZED)) { j.add("SUBSIZED"); }
return j.toString();
}
}
Parallel speed comes from a cheap trySplit, which comes from the source you chose.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Streams course, and every lesson in it is listed on the Streams contents page.