Start here. This is the direct spoken answer to practice first.
Overview
Stream operations are easiest to reason about when functions transform values instead of coordinating hidden mutable state.
Intermediate stream functions should usually be non-interfering and stateless: they should not modify the source or rely on mutable state that changes while the pipeline runs. Adding results to an external list inside forEach makes order, thread safety, and partial failure harder to reason about. Prefer map, filter, and collect to return the result as data. Side effects are sometimes necessary at a terminal boundary, but they should be explicit.