Skip to content

Streams — cheat sheet

From: fundamentals/12-streams.md.

Shape of a stream pipeline

Start → zero or more intermediate operations → exactly one terminal operation.

  • Start: collection.stream() or Stream.of(...).
  • Intermediate operations — each returns another stream, so they chain: map, filter, skip(n), limit(n), sorted()/sorted(Comparator).
  • Terminal operations — end the pipeline, produce a result, and a stream can only have one: collect(Collectors...), findFirst() (→ Optional), count(), forEach(lambda), reduce(...).
java
List<String> result = names.stream()
        .filter(name -> name.endsWith("sa"))
        .map(String::toUpperCase)
        .collect(Collectors.toList());

Lambda expressions

A lambda is a method with the name and return type dropped (both inferred): parameters, ->, body.

  • (a, b) -> { ...; ...; } — multi-line body needs braces and ; per statement.
  • (a, b) -> expr — single expression, no braces/; needed.
  • a -> expr — single parameter, parentheses optional.
  • () -> expr — no parameters, parentheses required.

Method reference (ClassName::methodName): shorthand for a lambda whose entire body is just calling one existing method with no extra logic, e.g. vowel -> vowel.toUpperCase() becomes String::toUpperCase.

Comparators (for sorted(...))

  • Comparator.naturalOrder() / reverseOrder() — delegate to each element's own compareTo.
  • Comparator.comparing(Class::getter) — sort by one attribute.
  • .reversed() — flip a comparator.
  • .thenComparing(Class::getter) — tiebreaker for equal primary comparisons.

Collectors (for collect(...))

  • Collectors.toList() — gather into a List.
  • Collectors.joining() / joining(delimiter) — concatenate strings, with an optional separator placed only between elements.

Other terminal operations

  • count() — number of elements.
  • forEach(lambda) — side-effect per element (e.g. printing).
  • reduce(lambda) — combine all elements into one (e.g. Integer::sum); returns Optional since the stream might be empty.
  • reduce(seed, lambda) — same, but returns seed if empty, and starts accumulation from seed otherwise (no Optional needed).

Why streams

Replaces repetitive manual loops (build a result list, loop, check a condition, maybe transform, add to result) with a declarative pipeline describing what to do to each element, not the loop mechanics of how. Worth being able to rewrite a simple for-loop-with-if as an equivalent stream on the spot, and vice versa.