skiwi
skiwi

Reputation: 69259

Is it possible to use an ordered Collector with a parallel stream?

When computing Cartesian Products using streams, I can produce them in parallel, and consume them in order, which the following code demonstrates:

int min = 0;
int max = 9;
Supplier<IntStream> supplier = () -> IntStream.rangeClosed(min, max).parallel();
supplier.get()
        .flatMap(a -> supplier.get().map(b -> a * b))
        .forEachOrdered(System.out::println);

This will print everything perfectly in order, now consider the following code where I want to add it to a list, while preserving the order.

int min = 0;
int max = 9;
Supplier<IntStream> supplier = () -> IntStream.rangeClosed(min, max).parallel();
List<Integer> list = supplier.get()
        .flatMap(a -> supplier.get().map(b -> a * b))
        .boxed()
        .collect(Collectors.toList());
list.forEach(System.out::println);

Now it does not print in order!
This is understandable given that I nowhere demand that the order should be preserved.

Now the question: Is there a way to collect() or is there a Collector that preserves order?

Upvotes: 6

Views: 453

Answers (1)

Rohit Jain
Rohit Jain

Reputation: 213223

When I executed your code, I got the outputs in order. In fact got the same output for both the code. It seems like the Collector returned from Collectors.toList is already ordered, as being depicted by following code:

Collector collector = Collectors.toList();
System.out.print(collector.characteristics());

it prints:

[IDENTITY_FINISH]

Since there is no UNORDERED characteristics set for the collector, it will process the elements in order only, and which is what the behaviour I'm seeing.

In fact this is clearly mentioned in the docs of Collectors.toList():

Returns:
a Collector which collects all the input elements into a List, in encounter order

Upvotes: 4

Related Questions