A financial application processes millions of transactions daily. The original code uses a for loop to aggregate transactions into a Map<Long, TransactionSummary> where the key is account ID. To improve performance, a developer refactors it using parallel streams: transactions.parallelStream() .collect(Collectors.toMap( Transaction::getAccountId, Function.identity(), (t1, t2) -> t1.merge(t2), // merging logic HashMap::new )); After deployment, they observe that the resulting map is smaller than expected and some transaction summaries are missing. Profiling shows the merge function is called infrequently, suggesting that the map is losing entries. What is the most likely cause and the correct fix?
In parallel streams, the default toMap collector uses HashMap which is not thread-safe. ConcurrentHashMap allows safe concurrent insertion and merging.
Why this answer
The issue is that `HashMap::new` is not thread-safe. When `parallelStream()` splits the stream into multiple threads, each thread creates its own `HashMap` for partial results. These partial maps are then merged using the collector's combiner, but `HashMap` does not guarantee thread safety during concurrent access or merging.
Using `ConcurrentHashMap::new` ensures that the map can be safely populated and combined across threads, preventing lost entries. The merge function itself is associative (merging two summaries into one), so the problem is purely the thread-unsafe map supplier.
Exam trap
Oracle often tests the misconception that the merge function must be associative when the real culprit is the thread-unsafe map supplier in parallel stream collectors.
How to eliminate wrong answers
Option A is wrong because removing parallelism is unnecessary; the core issue is the thread-unsafe map supplier, not parallelism itself. Option B is wrong because the merge function `(t1, t2) -> t1.merge(t2)` is associative (merging is order-independent) and not the cause of missing entries. Option C is wrong because using `forEach` with `ConcurrentHashMap` and `putIfAbsent` would work but is a manual, less idiomatic approach; the correct fix is to simply supply a thread-safe map to the collector, which is simpler and preserves the parallel stream's performance benefits.