Functional Programming & Streams

Stream Operations

The intermediate vocabulary — map, filter, flatMap, sorted, distinct, limit/skip, takeWhile/dropWhile — and the terminals: reduce, collect, find*, *Match, min/max, toList.
  • map transforms 1→1; flatMap transforms 1→many and flattens; mapMulti (Java 16) is its imperative sibling
  • takeWhile/dropWhile (Java 9) cut ordered streams at a condition
  • anyMatch/allMatch/noneMatch and findFirst/findAny short-circuit
  • reduce folds with an associative operation; collect builds containers
  • sorted, distinct are stateful — they buffer; keep them late and rare
flatMap: the un-nester
// All distinct words across all lines:
List<String> words = lines.stream()
        .flatMap(line -> Arrays.stream(line.split("\\s+")))  // Stream<String> per line → one stream
        .map(String::toLowerCase)
        .distinct()
        .toList();

// Optional-valued lookups compose the same way:
List<Order> orders = ids.stream()
        .map(repo::findOrder)              // Stream<Optional<Order>>
        .flatMap(Optional::stream)         // keep only present values
        .toList();
Terminals: reduce and friends
int totalChars = words.stream().mapToInt(String::length).sum();   // specialized reduce

Optional<String> longest = words.stream()
        .max(Comparator.comparingInt(String::length));

boolean anyEmpty = words.stream().anyMatch(String::isEmpty);       // stops at first hit

// General fold — identity, accumulator (must be associative):
int sum = numbers.stream().reduce(0, Integer::sum);

reduce's operation must be associative and stateless — that contract is what lets the same code run parallel unchanged (Parallel Streams). If your reduction builds a mutable container (a list, a map, a StringBuilder), that's not reduce, that's collect — the mutable-reduction terminal (Collectors).

Sources
  • Core Java, Volume II: Advanced Features (13th ed.)Ch. 1.3–1.7 — filter/map/flatMap; Substreams; Reductions; Optional
  • Effective Java (3rd ed.)Items 46, 47