ComparisonDifficulty: Intermediate1 min

map vs flatMap

A Stream<List<Invoice>> where you wanted a Stream<Invoice> is the symptom of choosing wrongly.

map and flatMap both apply a function to every element of a stream. map keeps one result per element; flatMap expects the function to return a stream and merges all of those streams into one.

Each customer below holds a list of invoices. Mapping each customer to that list gives a stream of lists; flat-mapping gives the invoices themselves, which is nearly always what the next step wanted:

What each one does with the value your function returns
Compared onmapflatMap
Your function returnsA valueA stream
The result isA stream of those valuesOne stream with every element of every returned stream
Element countExactly the sameAny number, including zero
java
Stream<List<Invoice>> nested = customers.stream().map(Customer::invoices);

Stream<Invoice> flat = customers.stream().flatMap(c -> c.invoices().stream());
line 1 gives a stream of lists; line 3 gives a stream of invoices

The decision rule. If your function returns one thing per element, map. If it returns several (a list, a stream, an Optional) and you want them all in one flat stream, flatMap. The element count tells you too: if the output can have more or fewer elements than the input, it is a flatMap.

The symptom is in the type. A Stream<List<X>> or a Stream<Stream<X>> in the middle of a pipeline is almost always a map that should have been a flatMap, and the compiler will tell you about it at the next step.