Stream API and Lambda

Basic Java
≈ 3 min read

Behavior as part of a program

Up to this point, code has mostly answered the question “what data do we have and which methods process it?” This section adds another important idea: an action itself can be passed as a value, and processing a sequence of data can be described as a chain of steps. Lambda expressions and the Stream API are built around exactly this idea.

After this section, a familiar task such as “take a list, keep matching elements, transform them, and get a result” will read like a sequential scenario rather than a set of nested loops and temporary collections.

What this section contains

  • Lambda expressions. We will learn to describe small pieces of behavior compactly right where they are used.
  • Functional interfaces. We will examine the types that lambda expressions fit into and the standard interfaces from java.util.function.
  • Method references. We will see a shorter form for cases where a lambda only calls an existing method or constructor.
  • Stream API basics. We will examine the source, pipeline, lazy execution, and the difference between a stream and a collection.
  • Intermediate operations. We will learn to filter, transform, sort, and limit a stream of data.
  • Terminal operations. We will see how a pipeline starts running and turns into a number, value, collection, or side effect.
  • Collectors. We will collect results into more complex structures: strings, groups, and maps.
  • Optional. We will examine an explicit representation of a situation where a result may be absent.
  • Primitive streams. We will get to know IntStream, LongStream, and DoubleStream.
  • Parallel streams. We will understand what changes with parallel execution and why it is far from suitable for every task.

The topics are arranged in this order for a reason. First, you need to learn how to pass behavior, then understand the types of that behavior, and only after that use it inside a stream pipeline. At the end of the section, we will add tools for collecting results, representing missing values, working with primitives, and parallel execution.

List<String> names = List.of("Ann", "Bob", "Alexander");

List<String> result = names.stream()
        .filter(name -> name.length() > 3)
        .map(String::toUpperCase)
        .toList();

For now, it is enough to notice the overall shape: data passes through several clear steps, and a new result is produced at the end. We will examine how each part of this chain works one page at a time.