16

While doing stream operations, during the intermediate/pipeline operations the streams would be created with different characteristics(e.g: SORTED/SIZED/DISTINCT/ORDERED) - Mastering Lambdas(Ch 6)

Stream.of(8,3,5,6,7,4) // ORDERED, SIZED
.filter(i->i%2==0) // ORDERED
.sorted() // ORDERED, SORTED
.distinct() // DISTINCT, ORDERED, SORTED
.map(i->i+1) // ORDERED
.unordered(); // none

How do we find out the different characteristics of the stream as mentioned in the above snippet?

Meenamma
  • 47
  • 8
Chota Bheem
  • 1,106
  • 1
  • 13
  • 31

2 Answers2

11

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);
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 4
    @Eugene: you can recreate the stream from the spliterator, [see here](https://stackoverflow.com/a/28475289/2711488), I suppose, this is what the OP is after… – Holger Jun 12 '17 at 06:56
  • 2
    @Holger ah! that would make sense to return a stream from that spliterator... thx. sincere congrats on the 100k. – Eugene Jun 12 '17 at 07:01
10

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.

Eugene
  • 117,005
  • 15
  • 201
  • 306