Short-circuiting & infinite streams in Java
limit and findFirst make infinite streams finite.
Stream.generate(() -> 1).count() — will it return a huge number, crash, or never finish? Infinite streams are powerful… if you know the off switch.Rivers that never end
Stream.iterate(seed, f) and Stream.generate(supplier) are infinite. Laziness makes that fine — values are produced only when pulled — as long as something stops the flow.
The stoppers
Short-circuiting ops can finish without seeing everything: **limit(n), takeWhile(p), findFirst, anyMatch… Ops that need every** element — count(), sorted(), toList() — never finish on an infinite stream. And **filter can't stop anything**: it never knows whether more matches will come.
Taking five
What does this print?
var r = Stream.iterate(1, n -> n * 3)
.limit(4)
.toList();
System.out.println(r);[3, 9, 27, 81][1, 3, 9, 27][1, 3, 9]
Show the answer
[1, 3, 9, 27] — iterate emits the seed first, then keeps tripling; limit(4) keeps four values.
Searching forever?
What does this print?
boolean found = Stream.iterate(1, n -> n + 1)
.anyMatch(n -> n * n > 30);
System.out.println(found);truefalseIt never finishes
Show the answer
true — at n = 6, 36 > 30, and anyMatch short-circuits right there. The infinite source is no problem.
takeWhile vs filter
**takeWhile(p) (Java 9) keeps elements until the first one that fails**, then stops completely. filter checks every element and keeps going.
Stream.of(2, 4, 5, 6)
.takeWhile(n -> n % 2 == 0); // [2, 4]
Stream.of(2, 4, 5, 6)
.filter(n -> n % 2 == 0); // [2, 4, 6]filter can't end infinity
This never finishes: filter(n -> n < 10) drops big numbers, but it can't know none will ever match again, so toList waits forever. Swap it for **takeWhile(n -> n < 10)**.
Stream.iterate(0, n -> n + 1)
.filter(n -> n % 2 == 0)
.filter(n -> n < 10) // never stops!
.toList();Infinite on purpose
Infinite streams model ID generators, retry back-offs (iterate(100, d -> d * 2)), and paginated APIs ("fetch next page until empty" with the 3-arg iterate or takeWhile). A missing stopper shows up as a hung thread and a CPU stuck at 100%.
Key takeaways
- limit(n) and takeWhile(p) cut an infinite stream short
- findFirst/anyMatch stop as soon as they have an answer
- filter can't stop a stream: it never knows if more will match
- count(), sorted() or toList() on an infinite stream never end
Stream.iterate(1, n -> n + 1) doesn't stop at Integer.MAX_VALUE — it silently overflows to negative numbers and keeps going.
Practice questions
What does this print?
List<Integer> r = Stream.iterate(2, n -> n * 2)
.limit(5)
.toList();
System.out.println(r);- [2, 4, 8, 16]
- [2, 4, 8, 16, 32]
- [4, 8, 16, 32, 64]
- [1, 2, 4, 8, 16]
Check your answer
[2, 4, 8, 16, 32]. iterate starts at the seed 2 and keeps doubling; limit(5) keeps the first five values.
What does this print?
int first = Stream.iterate(1, n -> n + 1)
.filter(n -> n * n > 50)
.findFirst()
.get();
System.out.println(first);- 7
- 8
- 50
- It never finishes
Check your answer
8. 7×7 = 49 is not > 50, but 8×8 = 64 is. findFirst stops pulling right there, so the infinite source is no problem.