A question about spliterators that at first glance is not straightforward.
In streams, .parallel()
changes the behaviour that the stream is processed. However I was expecting the spliterators created from sequential and parallel streams to be the same. For example, in sequential streams typically, the .trySplit()
is never invoked, while in parallel streams it is, in order to hand over the split spliterator to another thread.
Differences between stream.spliterator()
vs stream.parallel().spliterator()
:
They may have different characteristics:
Stream.of(1L, 2L, 3L).limit(2); // ORDERED Stream.of(1L, 2L, 3L).limit(2).parallel(); // SUBSIZED, SIZED, ORDERED
It seems another nonsense stream spliterator characteristics policy (in parallel seems better calculated) discussed here: Understanding deeply spliterator characteristics in java 8 and java 9
They may have different behaviour in terms of splitting using
.trySplit()
:Stream.of(1L, 2L, 3L); // NON NULL Stream.of(1L, 2L, 3L).limit(2); // NULL Stream.of(1L, 2L, 3L).limit(2).parallel(); // NON NULL
Why do the last two have different behaviours? Why I can't I split a sequential stream if I want to? (Could be useful to discard one of the splits for fast processing, for example).
Big impacts when transforming a spliterators to a stream:
spliterator = Stream.of(1L, 2L, 3L).limit(2).spliterator(); stream = StreamSupport.stream(spliterator, true); // No parallel processing!
In this case, a spliterator was created from a sequential stream which disables the ability to split (.trySplit()
returns null). When later, there is a need to transform back to a stream, that stream won't benefit from parallel processing. A shame.
The big question: As a workaround, what are the major impacts of always transforming a stream to parallel before invoking .spliterator()
?
// Supports activation of parallel processing later
public static <T> Stream<T> myOperation(Stream<T> stream) {
boolean isParallel = stream.isParallel();
Spliterator<T> spliterator = stream.parallel().spliterator();
return StreamSupport.stream(new Spliterator<T>() {
// My implementation of the interface here (omitted for clarity)
}, isParallel).onClose(stream::close);
}
// Now I have the option to use parallel processing when needed:
myOperation(stream).skip(1).parallel()...