Stream API and Lambda
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, andDoubleStream. - 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.