How to correctly find the stream characteristics in Java-8?

I would like to slightly extend what assylias said (which is absolutely correct).

First, these characteristics are implemented as plain int, it's binary representation. First it's all zeroes, but when you add a certain characteristic it's bit is set to one via the OR operation, removed via the AND operation.

You can see where a certain Spliterator property sets its one simply by doing this for example:

System.out.println(Integer.toBinaryString(Spliterator.SIZED)); // 1000000

It's setting the 7-th bit into one from the right. So when you check:

Spliterator<Integer> spliterator = Stream.of(8, 3, 5, 6, 7, 4).spliterator();
System.out.println((spliterator.characteristics() & Spliterator.SIZED) == Spliterator.SIZED);

You are actually checking if this particular bit is set.

Second

There are 4 stream characteristics that are set as the result of your first stream creation(and not two). Either the book is a bit outdated or you have not showed us the entire example:

Spliterator<Integer> spliterator = Stream.of(8, 3, 5, 6, 7, 4).spliterator();

System.out.println(Integer.bitCount(spliterator.characteristics())); // 4
System.out.println(Integer.toBinaryString(spliterator.characteristics()));// 100010001010000

These set bits (that are equal to one) correspond to SIZED, ORDERED, IMMUTABLE, SUBSIZED.

The others that you have shown are obviously slightly off too - you can check those yourself.

Third

These characteristics are extremely important in stream processing. A few examples:

long howMany = Stream.of(1, 2, 3).map(x -> {
        System.out.println("mapping");
        return x * 2;
    }).count();
    System.out.println(howMany); // 3

In java-9 you will not see the mapping printed, because you have not changed the stream (you have not cleared the SIZED characteristic); thus no need to even evaluate the mapping at all.

Stream<Integer> unlimited = Stream.iterate(0, x -> x + 1); 
System.out.println(unlimited.spliterator().hasCharacteristics(Spliterator.SIZED));
Stream<Integer> limited = unlimited.limit(3);          
System.out.println(limited.spliterator().hasCharacteristics(Spliterator.SIZED));

You would think that the output should be false true - we are adding a limit after all, but no; the result is false false: no such optimization is done, even if there is not much preventing it.


At each stage you can call:

int c = stream.spliterator().characteristics();

And then test the result against the constants defined in the Spliterator class. For example to see if the stream is ordered:

boolean isOrdered = (c & Spliterator.ORDERED) == Spliterator.ORDERED;

Alternatively you can use:

boolean isOrdered = stream.spliterator().hasCharacteristics(Spliterator.ORDERED);