Java Stream collect
collect is a terminal Stream operation that gathers stream elements into a result, often a mutable container such as a list. It can use a Collector or explicit supplier, accumulator, and combiner functions.
A stream pipeline can transform and filter elements, but it needs a terminal operation to produce a final result. `collect` performs a mutable reduction: instead of repeatedly replacing a value, it adds elements to a result container, such as an `ArrayList`.
The common form is `stream.collect(collector)`. A `Collector` describes how to create and update the result and how to combine partial results. Standard collectors support common outcomes, such as collecting elements into a list or grouping them.
There is also a three-argument form: `collect(supplier, accumulator, combiner)`. The supplier creates a result container, the accumulator adds one stream element to it, and the combiner merges two containers. For example, `ArrayList::new`, `ArrayList::add`, and `ArrayList::addAll` can be used for a list.
`collect` is terminal, so it produces a result rather than another stream. Its mutable reduction can work with parallel streams without requiring the caller to synchronize the result container, provided the reduction functions follow the required contracts.
Key points
- `collect` is a terminal operation that returns a result.
- A mutable reduction updates a result container as elements are processed.
- The Collector overload packages the rules for producing a result.
- The three-argument overload takes a supplier, accumulator, and combiner.
- A parallel collection relies on compatible combination behavior; do not share mutable state outside the collection.
Interview questions
What does `Stream.collect` do?
`collect` is a terminal operation that performs a mutable reduction. It incorporates stream elements into a result container, such as a list. The result is returned when collection finishes.
What are the three functions in `collect(supplier, accumulator, combiner)` for?
The supplier creates a result container. The accumulator incorporates one stream element into that container. The combiner merges two result containers, which is useful when partial results need to be joined.
How would you collect stream elements into a list using the Collector API?
Pass a list-producing collector to `collect`, for example `stream.collect(Collectors.toList())`. The stream's elements are accumulated into the resulting list. The operation is terminal, so it returns the list rather than another stream.
Why can `collect` support parallel streams without requiring synchronization on the result container?
The collection operation can build partial results and combine them rather than requiring every worker to update one shared container. The combiner joins partial containers. This depends on the collection functions obeying their required contracts; mutable state shared outside the operation still needs appropriate synchronization.