What is the difference between map() and flatMap() in streams?

8 minintermediatemapflatmapstreams

Quick Answer

map() applies a function to each element and produces exactly one output per input, resulting in a Stream of the same 'shape' (one-to-one transformation), which becomes a problem when the function itself returns a stream/collection per element (you'd get a stream of streams). flatMap() applies a function that returns a stream per element, then flattens all those inner streams into a single, flat output stream — used to transform-and-merge nested structures.

Detailed Answer

Both are intermediate stream operations that transform each element, but differ in cardinality — how many output elements one input element produces:

map(Function<T,R>): a strict one-to-one transformation — each input element produces exactly one output element (of possibly a different type).

Stream<String> names = Stream.of("Alice", "Bob");
Stream<Integer> lengths = names.map(String::length); // one Integer per String

If the mapping function itself naturally returns a collection/stream per element, map() produces a stream of streams, which is rarely what you want:

Stream<List<Integer>> nested = Stream.of("Alice", "Bob").map(name -> parseDigits(name));
// Stream<List<Integer>> — awkward to work with directly

flatMap(Function<T, Stream<R>>): applies a function that returns a stream per element, then flattens all those inner streams into one single, combined output stream — a one-to-many transformation followed by merging.

List<List<Integer>> nestedLists = List.of(List.of(1,2), List.of(3,4), List.of(5));
List<Integer> flat = nestedLists.stream()
    .flatMap(List::stream)   // Stream<List<Integer>> -> flattened Stream<Integer>
    .collect(Collectors.toList());
// [1, 2, 3, 4, 5]

A classic real-world use: given a List<Order> where each Order has a List<LineItem>, orders.stream().flatMap(o -> o.getLineItems().stream()) gives you a single flat Stream<LineItem> across all orders, ready for further filtering/aggregation — something map() alone can't produce directly.