Card 05/ 10
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:
| Compared on | map | flatMap |
|---|---|---|
| Your function returns | A value | A stream |
| The result is | A stream of those values | One stream with every element of every returned stream |
| Element count | Exactly the same | Any number, including zero |
Stream<List<Invoice>> nested = customers.stream().map(Customer::invoices);
Stream<Invoice> flat = customers.stream().flatMap(c -> c.invoices().stream());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.
← → move through sections and cards