Lesson 3 / 38

The Stream API

Build declarative pipelines over collections with filter, map and reduce, collect results with Collectors like groupingBy, and know when parallelStream helps.

Source, intermediate, terminal

A stream pipeline has a source (collection.stream()), zero or more lazy intermediate ops (filter, map, sorted, distinct, limit), and one terminal op (collect, forEach, reduce, count) that triggers execution. Streams don't mutate the source and can't be reused.

A real pipeline

Collectors build the result: toList, toSet, joining, groupingBy, partitioningBy, summingInt, averagingDouble.

Map<Dept, List<String>> byDept = employees.stream()
    .filter(e -> e.salary() > 50_000)
    .sorted(Comparator.comparing(Employee::name))
    .collect(Collectors.groupingBy(
        Employee::dept,
        Collectors.mapping(Employee::name, Collectors.toList())));

parallelStream() with care

parallelStream() splits work across the common ForkJoinPool. It only helps for large, CPU-bound, side-effect-free work with a cheap splitter (arrays, ArrayList). For small or IO-bound data it's usually slower.