4

In java 8 documentation (doc order stream), one can see this :

if [a stream] is not ordered, repeated execution might produce different results.

my question is quite simple : is there an easy way to illustrate this fact in a little unit test (maybe with an HashMap or some thing like this) ?

[Edit] the whole quote is here :

For sequential streams, the presence or absence of an encounter order does not affect performance, only determinism. If a stream is ordered, repeated execution of identical stream pipelines on an identical source will produce an identical result; if it is not ordered, repeated execution might produce different results.

Thus, my question is about a strictly sequential not parallele execution. It is this case that I'm questioning about.

Lyxthe Lyxos
  • 278
  • 2
  • 12
  • See [here](https://stackoverflow.com/a/41895946/2711488) – Holger Jul 06 '17 at 16:50
  • As I explained in comments under, the java documentation give explicitely this behavior in a stricly sequential and not parallel execution : "For sequential streams, the presence or absence of an encounter order does not affect performance, only determinism. If a stream is ordered, repeated execution of identical stream pipelines on an identical source will produce an identical result; if it is not ordered, repeated execution might produce different results." si my question is about this case not the parallele one – Lyxthe Lyxos Jul 07 '17 at 08:21
  • The explanation of the linked answer still holds. Regardless of being sequential or parallel, a stream is not going to shuffle elements around, it will only try to exploit the unorderedness if there’s a performance benefit. So when even the documentation suggests that there won’t be a performance difference in the sequential case, it implies that there won’t be a behavioral difference in the sequential case with the current implementation. As the linked answer says. And “might produce different results” does not mean “will produce different results”. – Holger Jul 07 '17 at 08:30

2 Answers2

4

The obvious answer is that whenever you use unordered you should get different results. For example using this:

int first = Arrays.asList(1, 2, 3, 4).stream()
           .unordered()
           .parallel()
           .findFirst()
           .get();
System.out.println(first);

should produce a result that is not always 1. Because the stream is unordered, so any result out of [1,2,3,4] is possible.

In java-8 this is not true, the stream pipeline does not take that unordered into account:

    @Override
    public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
                                     Spliterator<P_IN> spliterator) {
        return new FindTask<>(this, helper, spliterator).invoke();
    }

But things have change in java-9:

    @Override
    public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
                                     Spliterator<P_IN> spliterator) {
        // This takes into account the upstream ops flags and the terminal
        // op flags and therefore takes into account findFirst or findAny
        boolean mustFindFirst = StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags());
        return new FindTask<>(this, mustFindFirst, helper, spliterator).invoke();
    }

So running the same code under java-9 multiple times will produce a different result.

There are operations that are already unordered like Stream#generate and Stream#forEach.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • I do quite understand how such an example might produce different result over multiple execution since it uses a parallel execution. But as I understand the java 8 documentation on this matter, it could also be the case even in a sequential and not parallel exectuion. That was my question. It wasn't clear but I'd like an example of the behavior with a sequential execution exclusively. – Lyxthe Lyxos Jul 07 '17 at 08:18
  • @LyxtheLyxos as far as i understand and tried - sequentially this would be impossible at the moment. Streams don't do any randomization for unordered sequential processing. They *might* in future... That's the reason the specification is the way it is - it leaves the door open for changes – Eugene Jul 07 '17 at 08:24
  • @LyxtheLyxos un-related to streams, but randomization happens in other places. For example in the Immutable Collections in jdk-9. `Map.of...` or `Set.of` *do* have a randomization pattern, so the entries are laid down internally in a different order. – Eugene Jul 07 '17 at 08:27
2

the documentation of Stream#forEach is already said as below:

The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism.

so the following test should be pass:

List<Integer> ordered = Arrays.asList(1, 2, 3, 4);
List<Integer> unordered = new CopyOnWriteArrayList<>();

ordered.stream().parallel().forEach(unordered::add);

assertThat(unordered, not(equalTo(ordered)));

and the operation Stream#findAny also is nondeterministic.

holi-java
  • 29,655
  • 7
  • 72
  • 83
  • I do the same remark than the one above, I do quite understand how such an example might produce different result over multiple execution since it uses a parallel execution. But as I understand the java 8 documentation on this matter, it could also be the case even in a sequential and not parallel exectuion. That was my question. It wasn't clear but I'd like an example of the behavior with a sequential execution exclusively. – Lyxthe Lyxos Jul 07 '17 at 08:19
  • @LyxtheLyxos Hi, you can see here, there is another question , and there many links in it , maybe you intersting https://stackoverflow.com/questions/44954433/encounter-order-friendly-unfriendly-terminal-operations-vs-parallel-sequential-v/44955315#44955315 – holi-java Jul 07 '17 at 08:55
  • @LyxtheLyxos I think it can't be done in sequential stream, since `unordered` is not `shuffle`, it can't complete in a single `thread`. – holi-java Jul 07 '17 at 09:04
  • @holi-java well, the data could be randomized internally somehow... but that would be expensive no matter how you look at it – Eugene Jul 07 '17 at 09:07
  • @Eugene yeah, I think OP misunderstand the `ordering` section, it only describe a piece of code, just like as call `source.stream().collect(toList())` repeatedly, the result order depends on the `source` whether is or `ordered`, rather the `unordered` operation . – holi-java Jul 07 '17 at 09:13
  • @holi-java I don't think I misunderstood it. It says clearly that "For sequential streams [...] If a stream is not ordered, repeated execution of identical stream pipelines on an identical source might produce different results" Thus the quote says that It could be possible to have different outcome from repeated sequential (and so not parallele) executions of identical stream pipelines on an identical source. I really don't understant how it could be true but if the official documentation says so, I'd like to build an example to illustrate the fact. – Lyxthe Lyxos Jul 18 '17 at 12:59