简体   繁体   中英

Which stream operations use `CONCURRENT`,`IMMUTABLE` and `NONNULL` Spliterator characteristics?

Which stream operations use CONCURRENT , IMMUTABLE and NONNULL Spliterator characteristics? How does each of them help in those operations?


I'm not asking what those flags are, this can be found easly in the documantation. I'm asking which operations use them and how.

First, you should make a clear distinction that you are asking about Spliterator characteristics here and these depend on the source of the Stream; because there are also ( CONCURRENT , UNORDERED and IDENTITY_FINISH for Collectors for example).

There is a comment in StreamOpFlag saying:

// The following Spliterator characteristics are not currently used but a
// gap in the bit set is deliberately retained to enable corresponding
// stream flags if//when required without modification to other flag values.
//
// 4, 0x00000100 NONNULL(4, ...
// 5, 0x00000400 IMMUTABLE(5, ...
// 6, 0x00001000 CONCURRENT(6, ...
// 7, 0x00004000 SUBSIZED(7, ...

As far as I understand these are not a direct 1 to 1 mapping with the ones from Spliterator, but still they are not used.

At the moment (and I've searched the jdk-8 and 9 sources), neither are leveraged - but still are reported by some implementations of Spliterators ( Arrays report IMMUTABLE and ConcurrentHashMap reports NONNULL for example).

These flags could be used in the future on the other hand - if you know that a source can not contain null elements ( NONNULL ), obviously you can skip some null checks or define some state with a null. I can't think of any examples for CONCURRENT or IMMUTABLE , but there might be such.

For example under the current implementation for an UNORDERED and CONCURRENT collector (!= Spliterator properties), the combiner is not called when you do toConcurrentMap . For example:

Set.of("one", "two", "das", "dasda")
            .stream()
            .parallel()
            .collect(Collectors.toConcurrentMap(Function.identity(), String::length));

will not call the combiner - since there is no need to.

Optimizations like these could be made for any of the 3 characteristics that you have mentioned. For example you can read this where StreamOpFlag.ORDERED has changed the result of findFirst in java 8 vs java 9

In Java 8, the stream operations use neither of these 3 characteristics. This can be checked by searching these constants in the Java sources.

However, the CONCURRENT characteristic may affect the behaviour of parallel streams when you write your own collection. If you create a Spliterator from a collection and not report the CONCURRENT characteristic, then the spliterator will additionally have SIZED and SUBSIZED characteristics:

Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, 0);

System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints true
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints true

But if you report the CONCURRENT characteristic, then the spliterator is not SIZED anymore:

Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, Spliterator.CONCURRENT);

System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints false
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints false

Spliterators that are not SIZED and SUBSIZED are poorly parallelized, so when you write you own concurrent collection, it is better to write a custom spliterator and not rely on the default spliterator implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM