What they're testing
Whether you use streams because they read better, or because you believe they're faster than loops.
The short answer~30 seconds
Intermediate operations (map, filter) only build a pipeline; nothing runs until a terminal operation (collect, forEach, count). That fusion is what lets streams short-circuit — findFirst doesn't traverse everything. parallelStream() runs on the common ForkJoinPool SHARED across the whole JVM, so one blocking task there starves everything else; and on small lists the splitting overhead exceeds the saving.
The long answer
The easily-missed part of laziness: it changes HOW MANY TIMES your function runs. With list.stream().map(this::expensive).filter(x -> x > 0).findFirst(), expensive runs only until the first match — not across the whole list. Written as two separate loops you'd compute everything and then filter. That's the real benefit of streams, and it has nothing to do with parallelism.
With parallelStream(), the bigger issue than performance is resource sharing. The common pool has cores-minus-one threads, and EVERY parallelStream() in the process shares it. One place calling an external API inside a parallel stream occupies a thread for the whole network wait, and other parallel streams — possibly in an unrelated layer — queue behind it. If you genuinely need parallelism, submit to your own ForkJoinPool.
Beyond that, parallelStream() only wins when three things hold: the source splits cheaply (arrays, ArrayList — not LinkedList), the per-element work is substantial, and there's no shared state. In a web service a fourth condition matters more: you're ALREADY parallel at the request level, so parallelising inside merely competes with your own other requests for CPU.
What they'll ask next
?What's the trap in Collectors.toMap?
It throws IllegalStateException on duplicate keys rather than silently overwriting as you might expect. You must pass a merge function as the third argument. It also throws NPE on null values, unlike an ordinary HashMap.
?Can a stream be reused?
No. A stream is consumed once; a second terminal operation throws IllegalStateException. To traverse again, create a new stream from the source, or pass a Supplier<Stream<T>> if it needs to travel.
These lose points
- Using
parallelStream()as a default speed-up. In a web application it almost always makes p99 worse. - Mutating an outside variable inside
forEach. It breaks correctness under parallelism and destroys any ability to reason about the pipeline.