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.