Skip to content
AgileLogics
6 min read

Streams

Prerequisites: Lambda expressions & functional interfaces

A Stream describes a pipeline of operations over a collection — filter, transform, and collect — without writing an explicit loop.

List<String> names = List.of("Ada", "Bob", "Grace", "Al");

List<String> longNames = names.stream()
    .filter(name -> name.length() > 2)
    .map(String::toUpperCase)
    .sorted()
    .toList();

System.out.println(longNames); // [ADA, GRACE]

A stream is lazy — nothing runs until a terminal operation like .toList(), .forEach(), or .count() is called — and it can only be consumed once.

Common mistakes

  • Reusing a Stream variable after a terminal operation already ran on it — throws IllegalStateException. Build a fresh stream (e.g. call .stream() again) each time.
  • Reaching for a stream pipeline when a plain for-each loop would be clearer — streams shine for filter/transform/collect chains, not every loop.

Practice

Given List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);, use a stream to produce a list of only the even numbers, doubled.

Show solution
List<Integer> result = nums.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * 2)
    .toList();
// [4, 8, 12]