You build an infinite stream with Stream.iterate and add sorted(). What happens, and which intermediate operations are safe on an infinite stream?
answer
- Infinite stream: only short-circuit ends it
- sorted = full barrier -> hangs / OutOfMemoryError
- Safe: map, filter, flatMap, peek, limit
- Pattern: limit BEFORE sorted/distinct
- distinct's seen-set grows unbounded -> unsafe unbounded
basics
~20 ssorted hangs forever (or runs out of memory) because it must see every element first, and an infinite stream never ends. Stateless ops like map and filter, plus the short-circuiting limit, are safe on infinite streams.
solid answer
~40 sAn infinite stream (e.g. Stream.iterate) never completes. sorted is a full-barrier stateful op: it must absorb all elements before emitting any, so on an infinite source it either hangs forever consuming elements or throws OutOfMemoryError. The same applies to anything that needs the whole input. What is safe: stateless ops (map, filter, flatMap, peek), which process element-by-element; and short-circuiting ops, especially limit, which stop pulling once they have enough. The idiomatic pattern is to put limit before any full-barrier op: Stream.iterate(...).filter(...).limit(n).sorted() works because limit makes the stream finite before sorted runs. Distinct is technically streaming but its seen-set grows unbounded on an infinite source, so treat it as unsafe too unless bounded by a prior limit.
code
java · 9 lines// SAFE: bound the stream before the barrier
List<Integer> ok = Stream.iterate(1, n -> n + 1)
.map(n -> n * n) // stateless
.limit(10) // short-circuit -> now finite
.sorted() // safe on 10 elements
.toList();
// UNSAFE: sorted runs first and never finishes
// Stream.iterate(1, n -> n + 1).sorted().limit(10).toList();go deeper
Knows sorted on an infinite stream hangs/runs out of memory and that limit is needed to bound it.
Explains the barrier vs short-circuit distinction, why stateless ops and limit are safe, and the limit-before-sorted ordering rule.
Adds nuance about distinct's unbounded seen-set, short-circuiting terminals (findFirst/anyMatch), and that parallelism doesn't rescue an unbounded barrier.
Frames infinite-stream safety as a property to encode in API/lint guidance, distinguishing short-circuiting from barrier ops and reviewing pipelines for unbounded state.
## What an infinite stream is Factories like `Stream.iterate(seed, next)` and `Stream.generate(supplier)` produce **unbounded** streams: they can keep yielding elements forever. They only terminate if something downstream **short-circuits** (stops pulling). ## Why sorted hangs `sorted` is a **full-barrier** stateful op: it cannot emit its first (smallest) element until it has seen *every* element, because order is global. On an infinite source 'every element' never arrives, so `sorted`: - keeps pulling elements forever (the program appears to hang), and - buffers them all, so it will eventually throw **`OutOfMemoryError`** once the heap fills. The same fate awaits any operation or terminal that must consume the whole stream before producing a result (e.g. `count`, `toList` without a prior `limit`, or a `collect` of the full stream). ## What is safe on an infinite stream 1. **Stateless intermediate ops** — `map`, `filter`, `flatMap`, `peek`. They transform each element as it flows and never need to wait for the end, so they coexist happily with an infinite source. 2. **Short-circuiting ops** — most importantly **`limit(n)`**, which converts the infinite stream into a finite one by stopping the source after `n` elements. Short-circuiting terminals like `findFirst`, `anyMatch`, `allMatch` also work because they can finish early. ## The idiomatic pattern: limit before the barrier ```java // SAFE: limit makes it finite BEFORE sorted runs List<Integer> firstSorted = Stream.iterate(100, n -> n - 1) .filter(n -> n % 2 == 0) // stateless, fine on infinite .limit(20) // now finite .sorted() // safe: operates on 20 elements .toList(); // BROKEN: sorted runs before any bound -> hangs / OOM // Stream.iterate(0, n -> n + 1).sorted().limit(20).toList(); ``` Order matters: `limit` must come **before** the barrier. Putting `sorted` first means the barrier tries to consume the infinite source before `limit` ever gets a chance to cut it off. ## A note on distinct and skip - **`distinct`** streams elements out as it confirms they're new, so it doesn't strictly barrier — but it accumulates a **seen-set** that grows without bound on an infinite stream of distinct values, so it is unsafe in practice unless a prior `limit` bounds it. - **`skip(n)`** is fine: it discards the first `n` and then passes through, never needing the whole stream. ## Mental model Ask: 'Does this op need to reach the end of the stream before it can produce output (or does it grow unbounded state)?' If yes, it's unsafe on an infinite stream. `sorted` (and full reductions) are the classic traps; `limit` is the classic rescue.
- Does Stream.iterate(0, n -> n+1).limit(5).sorted() work, and why?Yes. limit(5) short-circuits the infinite source to 5 elements first, so sorted then operates on a finite 5-element stream and completes normally.
- Is findFirst safe after a filter on an infinite stream?Yes. findFirst is short-circuiting: it stops pulling as soon as the filter yields one matching element, so the infinite source never runs forever.
saying these in an interview costs you the question
- Putting limit after sorted on an infinite stream and expecting it to work — sorted never finishes.
- Assuming distinct is safe on an infinite stream — its seen-set grows without bound.
- Thinking the stream errors immediately — it usually hangs first, then OOMs.
- Believing parallel makes sorted finite — parallelism doesn't make an infinite source terminate.