Understanding sequential vs parallel stream spliterators in Java 8 and Java 9

自古美人都是妖i 提交于 2019-12-01 09:01:14

This is not a general property of spliterators, but only of wrapping spliterators encapsulating a stream pipeline.

When you are calling spliterator() on a stream that has been generated from a spliterator and has no chained operation, you’ll get the source spliterator which may or may not support trySplit, regardless of the stream parallel state.

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "foo", "bar", "baz");
Spliterator<String> sp1 = list.spliterator(), sp2=list.stream().spliterator();
// true
System.out.println(sp1.getClass()==sp2.getClass());
// not null
System.out.println(sp2.trySplit());

likewise

Spliterator<String> sp = Stream.of("foo", "bar", "baz").spliterator();
// not null
System.out.println(sp.trySplit());

But as soon as you chain operations before calling spliterator(), you will get a spliterator wrapping the stream pipeline. Now, it would be possible to implement dedicated spliterators performing the associated operation, like a LimitSpliterator or a MappingSpliterator, but this has not been done, as converting a stream back to a spliterator has been considered as last resort when the other terminal operations do not fit, not a high priority use case. Instead, you will always get an instance of the single implementation class that tries to translate the inner workings of the stream pipeline implementation to the spliterator API.

This can be quiet complicated for stateful operations, most notably, sorted, distinct or skip&limit for a non-SIZED stream. For trivial stateless operations, like map or filter, it would be much easier to provide support, as has been even remarked in a code comment

Abstract wrapping spliterator that binds to the spliterator of a pipeline helper on first operation. This spliterator is not late-binding and will bind to the source spliterator when first operated on. A wrapping spliterator produced from a sequential stream cannot be split if there are stateful operations present.

…

   // @@@ Detect if stateful operations are present or not
   //     If not then can split otherwise cannot

   /**
    * True if this spliterator supports splitting
    */
   final boolean isParallel;

but it seems that currently this detection has not been implemented and all intermediate operations are treated like stateful operations.

Spliterator<String> sp = Stream.of("foo", "bar", "baz").map(x -> x).spliterator();
// null
System.out.println(sp.trySplit());

When you try to work-around this by always calling parallel, there will be no impact when the stream pipeline consists of stateless operations only. But when having a stateful operation, it might change the behavior significantly. E.g., when you have a sorted step, all elements have to be buffered and sorted, before you can consume the first element. For a parallel stream, it will likely use a parallelSort, even when you never invoke trySplit.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!