A pipeline tells a data-processing story: data enters, each stage transforms it, and a final operation produces a result. It separates data from behavior, replacing control-flow detail with a readable sequence of named transformations. section 6.3 section 6.5
Figure 6.2 A functional pipeline: transforming raw data
View a pipeline as data flowing through behavioral stages, like raw material being filtered and reshaped before it reaches an output. section 6.3
Build a pipeline in three parts:
- Creation: expose a data source through a structure that can apply transformations step by step. section 6.3.1
- Intermediate operations: add lazy steps such as filter, map, or flatMap; they define behavior but process no data yet. section 6.3.1 section 6.5
- Terminal operation: trigger execution and materialize a result with operations such as toList, collect, or count. A Java stream is then consumed and cannot be reused. section 6.3.1 section 6.5
Recent authors
Start with books, filter to those published within the last year, map each remaining Book to its author, then collect the names. The chain reads top-down as intent: select recent books, extract authors, make a list. Java streams, Kotlin sequences, C# LINQ, Python generator expressions, and Haskell can express comparable flows with different syntax. section 6.3.1
Keep a pipeline short enough to understand as a whole. Each operation is a chunk of logic; once a chain becomes a riddle, group related filters, extract well-named methods, or store an intermediate result and continue in a second stage. section 6.3.3 section 6.5
Do not force every task into a pipeline. File access, database updates, network messages, mutation-heavy algorithms, and exception-prone operations can make an imperative approach clearer. Prefer pipelines when composition makes the flow explicit; keep any impurity visible. section 6.3.2 section 6.4















































