I have a test code like this :
List<Integer> list = new ArrayList<>(1000000);
List<String> values = new ArrayList<>(1000000);
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. For any given element, the action may be performed at whatever time and in whatever thread the library chooses.
In your second example, you end up with multiple threads calling
add on the array list at the same time and
ArrayList documentation says:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
If you change the use of an
ArrayList to a
Vector, you'll get the correct result, because this list implementation is synchronized. Its Javadoc says:
Unlike the new collection implementations,
However, do not use it! Furthermore, it might end up being slower because of the explicit synchronization.
List<String> values = list.stream().map(i -> "foo").collect(Collectors.toList());
will always provide the correct result, whether run in parallel or not. The Stream pipeline internally handles the concurrency and guarantees that it is safe to use a non-concurrent collector in a collect operation of a parallel stream.
Collectors.toList() is a built-in collector accumulating the elements of a Stream into a list.