Definition
- **Stream.iterate(seed, operator)** starts with a seed and applies the operator repeatedly: `iterate(1, n -> n * 2)` gives 1, 2, 4, 8, 16... INFINITE. - **Stream.iterate(seed, hasNext, next)** (Java 9) adds a predicate to stop: `iterate(1, n -> n <= 100, n -> n * 2)`. - **Stream.generate(supplier)** calls the supplier repeatedly: `generate(Math::random)` gives infinite random doubles. - **IntStream.range(start, end)** produces `start` to `end-1` (exclusive end). `rangeClosed(start, end)` includes end. - **.boxed()** converts `IntStream` to `Stream<Integer>` for operations requiring objects. - Infinite streams MUST be bounded with `limit(n)` or `takeWhile()` before any terminal operation.
At National Bank of India, iterate(principal, b -> b.multiply(rate)) is like a compound interest calculator that computes the balance month after month forever. You must tell it to stop after 12 months (limit(12)). generate(UUID::randomUUID) is like a token machine that creates transaction IDs forever. range(1, 10) is a numbered list of the first 9 account slots.
Understanding the Concepts
How does Stream.iterate work?
package com.bank.util;
import java.math.BigDecimal;
import java.util.stream.*;
public class StreamFactoryDemo {
public static void main(String[] args) {
// Infinite sequence: powers of 2
Stream.iterate(1, n -> n * 2)
.limit(10)
.forEach(n -> System.out.print(n + " "));
System.out.println();
}
}
1 2 4 8 16 32 64 128 256 512
How does bounded iterate work (Java 9)?
// Java 9: iterate with stop condition
Stream.iterate(1, n -> n <= 512, n -> n * 2)
.forEach(n -> System.out.print(n + " "));
1 2 4 8 16 32 64 128 256 512
How does Stream.generate work?
// Generate 5 random transaction amounts
Stream.generate(() -> BigDecimal.valueOf(Math.random() * 100000))
.limit(5)
.map(bd -> bd.setScale(2, java.math.RoundingMode.HALF_UP))
.forEach(amount -> System.out.println("Amount: Rs." + amount));
How do IntStream.range and rangeClosed work?
// range: exclusive end (0 to 4)
IntStream.range(0, 5).forEach(i -> System.out.print(i + " "));
// 0 1 2 3 4
// rangeClosed: inclusive end (1 to 5)
IntStream.rangeClosed(1, 5).forEach(i -> System.out.print(i + " "));
// 1 2 3 4 5
Why must infinite streams be bounded?
// HANGS: sorted() buffers ALL elements -- infinite stream never finishes
Stream.iterate(1, n -> n + 1)
.sorted() // tries to collect infinite elements!
.limit(5) // never reached
.forEach(System.out::println);
// CORRECT: limit BEFORE sorted
Stream.iterate(1, n -> n + 1)
.limit(5) // bounds the stream to 5 elements
.sorted() // sorts only 5 elements
.forEach(System.out::println);
What is boxed() for?
// IntStream has no collect(toList()) -- must box first
List<Integer> boxed = IntStream.rangeClosed(1, 5)
.boxed() // IntStream → Stream<Integer>
.toList();
// [1, 2, 3, 4, 5]
How do you use iterate for banking calculations?
// Monthly compound interest: 12 months
BigDecimal principal = new BigDecimal("100000");
BigDecimal monthlyRate = new BigDecimal("1.005"); // 0.5% monthly
Stream.iterate(principal, b -> b.multiply(monthlyRate))
.limit(13) // month 0 through 12
.forEach(b -> System.out.println("Balance: Rs." + b.setScale(2, java.math.RoundingMode.HALF_UP)));
What are common mistakes?
WRONG: Calling a terminal operation on an infinite stream without limit.
WRONG: Putting limit after sorted/distinct on an infinite stream.
What should a senior engineer know?
- Because streams are lazy,
limit(n)on an infinite stream produces exactly n elements without computing more. Stream.iteratewith the three-argument form (Java 9) is the stream equivalent of a traditional for-loop:for (int i = seed; hasNext(i); i = next(i)).Stream.generateis useful for random test data generation and for producing sequences where each element is independent (no state carried from the previous element).- For integer ranges, prefer
IntStream.range/rangeClosedoverStream.iterate(0, n -> n + 1).limit(n)because the range version supports parallel splitting more efficiently.
Visual Overview
Stream.iterate(1, n -> n * 2):
seed=1 → 2 → 4 → 8 → 16 → 32 → ... (infinite)
│
▼ limit(5)
[1, 2, 4, 8, 16]
Stream.generate(Math::random):
0.73 → 0.21 → 0.85 → 0.44 → ... (infinite)
│
▼ limit(3)
[0.73, 0.21, 0.85]
IntStream.range(0, 5): [0, 1, 2, 3, 4]
IntStream.rangeClosed(1,5): [1, 2, 3, 4, 5]
Key Takeaway
Three stream factories cover most creation needs. Stream.iterate creates infinite sequences by applying an operator repeatedly (powers of 2, Fibonacci, compound interest). Stream.generate calls a supplier infinitely (UUIDs, random numbers). IntStream.range/rangeClosed creates bounded integer ranges.
Infinite streams MUST be bounded with limit(n) or takeWhile before any terminal operation. Placing sorted() before limit() on an infinite stream hangs because it tries to buffer all elements. Always place the bounding operation early in the pipeline.
At National Bank of India, monthly compound interest is modeled with Stream.iterate(principal, b -> b.multiply(rate)).limit(12), producing 12 monthly balance snapshots in one pipeline.
Remember one sentence: iterate and generate produce infinite streams that must be bounded with limit, and rangeClosed includes the end value while range excludes it.
---