Lazy and Eager Processing¶
Eager processing performs work before the result is requested. Lazy processing defers work until consumption. Laziness can avoid unnecessary computation and support pipelines; eagerness can make cost, errors, snapshots, and resource ownership easier to reason about.
The three times to distinguish¶
For a lazy value, separate:
- construction of the recipe;
- traversal or evaluation;
- release of resources retained by the recipe.
Java Stream intermediate operations are lazy and a terminal operation begins traversal. A stream is single-use. If its source is mutable, results depend on the source state when traversal occurs, not necessarily when the pipeline was declared.
List<String> normalized = names.stream()
.filter(Objects::nonNull)
.map(String::strip)
.filter(name -> !name.isEmpty())
.toList();
toList() establishes an eager materialization boundary. That boundary can be
valuable before leaving a transaction, closing a file, or handing data to
another thread.
Persistence hazards¶
ORM lazy associations may issue a query when traversed. Access after the persistence context closes can fail; access inside a loop can create the N+1 query problem. Blanket eager fetching is not a solution: it can load unused graphs or multiply rows. Fetch exactly what a use case needs with a projection, explicit query, or carefully selected graph.
Concurrency and repeated work¶
Lazy initialization shared between threads needs safe publication and a stated failure policy. A thread-safe reference alone may still permit duplicate work. Also decide whether a failed initialization may be retried. A lazy sequence that recomputes on every traversal is different from memoization, which retains results.
Decision questions¶
- Is the result likely to be unused or only partly consumed?
- Must errors happen at a predictable boundary?
- Does evaluation retain a file, connection, transaction, or large object graph?
- Is a stable snapshot required?
- Will repeated traversal repeat expensive or observable work?
Prefer explicit materialization at ownership and resource boundaries. Use laziness where deferred or partial evaluation has measurable value.