javajava-streamspliterator

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.


Solution

  • 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