6

I have the following:

LinkedList<Integer> ints = new LinkedList();
//fill it with some ints
Stream<Integer> stream = ints.stream();
//process the stream in some way

My question is if it's guaranteed that the order of processing of the stream is as of the underlying LinkedList? I read the documentation but there was no any info about the ordering.

In my case it's critically to preserve the order.

Alexis C.
  • 91,686
  • 21
  • 171
  • 177
user3663882
  • 6,957
  • 10
  • 51
  • 92
  • 3
    The stream will be ordered, which guarantees a *result* with properly ordered elements, also known as *encounter order*. This has nothing to do with the *processing order*. See http://stackoverflow.com/a/29218074/2711488 – Holger Jul 08 '16 at 08:37
  • It all depends on what you do in "process the stream in some way". – JB Nizet Jul 08 '16 at 08:38
  • @JBNizet For instance with `map`. I mean mapped elements... will they have the same order as the LinkedList has? – user3663882 Jul 08 '16 at 08:40
  • Yes, it will. Unless you make the stream parallel, for example. – JB Nizet Jul 08 '16 at 08:41
  • 1
    If you say `List result=ints.stream().map(func).collect(Collectors.toList());`, the result list will have the elements in a matching order. This does not say anything about the order, in which the mapping function is evaluated, though. This applies to both, sequential and parallel streams. – Holger Jul 08 '16 at 08:42
  • @JBNizet Great, got it, thanks much. – user3663882 Jul 08 '16 at 08:42
  • 3
    @JB Nizet: there is no guaranty about the *processing order*, even for sequential streams. On the other hand, there are guarantees regarding the *encounter order*, even for parallel streams. – Holger Jul 08 '16 at 08:44
  • 1
    Note that this requirement about the order of processing is a big sign of something wrong in your design. It probably means that the mapping function is not a pure function, or has side effects, or is not idempotent. Why do you care the the first element is mapped before the second one? All that should matter is that the result is ordered as you want to. – JB Nizet Jul 08 '16 at 08:45
  • @Holger It sounds a little strange. If the stream is suquential and the result has the same order, why would we want to evaluate a function in a different one? – user3663882 Jul 08 '16 at 08:45
  • 1
    Related: http://stackoverflow.com/questions/29709140/why-parallel-stream-get-collected-sequentially-in-java-8/29713386 – Alexis C. Jul 08 '16 at 08:46
  • 1
    @Holger noted. I'd be surprised if the processing order was different, though, but I agree that relying on that is a smell anyway. – JB Nizet Jul 08 '16 at 08:46
  • @JBNizet Percisely, I need to implement some kind of "chained processing". I mean I have a chain of elements (LinkedList) which is supposed to be processed in the exact previous->next order. Streams seem to not suit to that task. – user3663882 Jul 08 '16 at 08:47
  • 1
    given your comments you should refine your question. it's lacking details of what you expect and why you expect it. also note that `.stream()` in itself does essentially nothing, what follows after it has a huge impact on how the stream is processed. – the8472 Jul 08 '16 at 08:50
  • 1
    @JB Nizet: there might be no imaginable scenario for a sequential implementation yet, still, there are no guarantees made. I remember a question on SO regarding this topic, where it was revealed that a sentence saying that processing order for sequential stream matches encounter order was deliberately removed from the documentation before the first Java 8 release, which might tell us something… – Holger Jul 08 '16 at 08:50
  • Yes, they can. For example: `ints.stream().map(i -> toProcess(i)).forEachOrdered(process -> process.run());`. Posting your code would help. – JB Nizet Jul 08 '16 at 08:50
  • @Holger yes, I understand the difference between a guarantee and an observed behavior :-) – JB Nizet Jul 08 '16 at 08:52
  • 2
    @JB Nizet: of course, I assumed that you know. But I wanted to emphasize that while the documentation does not say explicitly that we don’t have such a guaranty, a contradicting statement has been deliberately removed, telling us that the authors wanted to avoid the impression of having such a guaranty. – Holger Jul 08 '16 at 08:57
  • 1
    @user3663882: by the way, this looks exactly like a use case for `ArrayList` rather than `LinkedList` (like most use cases do). – Holger Jul 08 '16 at 08:59

2 Answers2

2

From the documentation:

Streams may or may not have a defined encounter order. Whether or not a stream has an encounter order depends on the source and the intermediate operations. Certain stream sources (such as List or arrays) are intrinsically ordered, whereas others (such as HashSet) are not. Some intermediate operations, such as sorted(), may impose an encounter order on an otherwise unordered stream, and others may render an ordered stream unordered, such as BaseStream.unordered(). Further, some terminal operations may ignore encounter order, such as forEach().

If a stream is ordered, most operations are constrained to operate on the elements in their encounter order; if the source of a stream is a List containing [1, 2, 3], then the result of executing map(x -> x*2) must be [2, 4, 6]. However, if the source has no defined encounter order, then any permutation of the values [2, 4, 6] would be a valid result.

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.

For parallel streams, relaxing the ordering constraint can sometimes enable more efficient execution...

Also, as you mentioned that processing order matters for you see here:

Stream pipeline results may be nondeterministic or incorrect if the behavioral parameters to the stream operations are stateful...

The best approach is to avoid stateful behavioral parameters to stream operations entirely; there is usually a way to restructure the stream pipeline to avoid statefulness.

See also the answer to this question: How to ensure order of processing in java8 streams?

In short, it looks like you can preserve the order, if you use sequential streams (streams that are executed in one thread) and if you are careful with operations like forEach(). However it probably is not a good idea.

Community
  • 1
  • 1
Alexey
  • 2,542
  • 4
  • 31
  • 53
1

Depends on the processing you are applying to the stream... especially using parallel()

import java.util.LinkedList;
import java.util.function.Consumer;
import java.util.stream.Stream;

public class Streaming {

    public static void main(String[] args) {
        LinkedList<Integer> ints = new LinkedList();
        for(int i = 0 ; i < 100; i++) {
            ints.add(i);
        }
        Stream<Integer> stream = ints.stream();
        // will not be ordered
        stream.parallel().forEach(new Consumer<Integer>() {

            @Override
            public void accept(Integer t) {
                System.out.println(t);
            }

        });

        stream = ints.stream();
        // will be ordered
        stream.parallel().forEachOrdered(new Consumer<Integer>() {

            @Override
            public void accept(Integer t) {
                System.out.println(t);
            }

        });
    }
}
Nicolas Modrzyk
  • 13,961
  • 2
  • 36
  • 40
  • 6
    Any reason for using anonymous inner classes in Java 8 code? I mean, especially *for this use case*? – Holger Jul 08 '16 at 09:00
  • Eclipse will generate them when you press `Command+Space`. It won't generate the Lambdas. :/ – ifly6 Jul 08 '16 at 10:52
  • 2
    @ifly6: So, instead of pressing `Command+Space`, you have to type `t` `-` `>`, in other words, press three keys instead of two. The effort for inserting the actual print statement is exactly the same. – Holger Jul 08 '16 at 11:35