Generating Streams
Creating streams without a collection — range(), rangeClosed(), iterate(), generate(), infinite streams, Fibonacci, UUIDs and business days.
#Introduction
Until now we've been processing existing collections:
List<Employee> employees = ...;
employees.stream();But what if there's no collection? How do you generate numbers from 1 to 100, a Fibonacci sequence, prime numbers, infinite random numbers, timestamps or test data? This is where stream generation comes in.
By the end of this chapter you'll master IntStream.range(), IntStream.rangeClosed(), Stream.iterate(), Stream.generate(), infinite streams, Fibonacci generation, even/odd sequences and random numbers.
Stream Sources So Far
So far we've created streams from List.stream(), Arrays.stream() and Stream.of(). Now we'll create streams without any existing data.
#IntStream.range()
Generate a sequence of numbers.
IntStream.range(1, 6)
.forEach(System.out::println);1
2
3
4
5Notice: 6 is NOT included. Think of it like a for loop — exactly the same:
for (int i = 1; i < 6; i++) {
System.out.println(i);
}#rangeClosed()
Now include the end value.
IntStream.rangeClosed(1, 6)
.forEach(System.out::println);1
2
3
4
5
6Equivalent to:
for (int i = 1; i <= 6; i++) {
System.out.println(i);
}range() vs rangeClosed()
| range() | rangeClosed() | |
|---|---|---|
| End value | Exclusive | Inclusive |
(1, 5) gives | 1 2 3 4 | 1 2 3 4 5 |
This is asked surprisingly often.
#Range Examples
Sum 1 to 100 — without loops
int sum = IntStream.rangeClosed(1, 100)
.sum();
System.out.println(sum);5050Even and Odd Numbers
// Even: 2, 4, 6, ... 20
IntStream.rangeClosed(1, 20)
.filter(n -> n % 2 == 0)
.forEach(System.out::println);
// Odd: 1, 3, 5, ... 19
IntStream.rangeClosed(1, 20)
.filter(n -> n % 2 != 0)
.forEach(System.out::println);Square Numbers
IntStream.rangeClosed(1, 5)
.map(n -> n * n)
.forEach(System.out::println);1
4
9
16
25#Stream.iterate()
Creates a sequence based on the previous value.
Stream.iterate(seed, nextFunction)Stream.iterate(1, n -> n + 1)
.limit(5)
.forEach(System.out::println);1
2
3
4
5Why limit()?
This never ends:
Stream.iterate(1, n -> n + 1)Without limit() the stream is infinite. Always combine infinite streams with .limit(...), otherwise your program won't terminate.
Even Numbers and Multiples
// 2, 4, 6, 8, ... 20
Stream.iterate(2, n -> n + 2)
.limit(10)
.forEach(System.out::println);
// 5, 10, 15, ... 50
Stream.iterate(5, n -> n + 5)
.limit(10)
.forEach(System.out::println);#Fibonacci Series
Interview favourite. Instead of storing previous numbers manually:
Stream.iterate(
new int[]{0, 1},
arr -> new int[]{arr[1], arr[0] + arr[1]}
)
.limit(10)
.map(arr -> arr[0])
.forEach(System.out::println);0
1
1
2
3
5
8
13
21
34How It Works
Each array stores [current, next]:
Very elegant.
#Stream.generate()
Unlike iterate(), this doesn't depend on previous values. Every element is created independently.
Stream.generate(Supplier)Stream.generate(() -> "Hello")
.limit(5)
.forEach(System.out::println);Hello
Hello
Hello
Hello
HelloRandom Numbers
Stream.generate(Math::random)
.limit(5)
.forEach(System.out::println);0.62…
0.18…
0.94…
…Every run is different.
UUID Generation
Very common in backend development.
Stream.generate(UUID::randomUUID)
.limit(3)
.forEach(System.out::println);4d1…
ab9…
ff2…Timestamp Generation
Stream.generate(LocalDateTime::now)
.limit(3)
.forEach(System.out::println);Useful for testing.
#iterate() vs generate()
| iterate() | generate() |
|---|---|
| Depends on the previous value | Independent values |
| Creates sequences | Creates random / repeated values |
| Fibonacci, arithmetic progressions | UUIDs, random numbers |
#Java 9 Enhancement
Java 9 introduced a three-argument iterate() with a stop condition:
Stream.iterate(1, n -> n <= 10, n -> n + 1)No limit() required. Unfortunately, this isn't available in Java 8 — for Java 8 interviews, know the original two-argument version.
#Real Spring Boot Examples
// Generate test IDs
List<String> ids = Stream.generate(UUID::randomUUID)
.limit(100)
.map(UUID::toString)
.toList();
// Generate dates — next 7 days
Stream.iterate(LocalDate.now(), date -> date.plusDays(1))
.limit(7)
.forEach(System.out::println);Retry Delays (Exponential Backoff)
Stream.iterate(1, n -> n * 2)
.limit(5)
.forEach(System.out::println);1
2
4
8
16#Interview Questions
Q1Difference between range() and rangeClosed()?
range()excludes the end value.rangeClosed()includes the end value.
Q2Difference between iterate() and generate()?
iterate()depends on the previous element.generate()creates independent elements.
Q3Why use limit() with generate()?
Because generate() produces an infinite stream.
Q4Can iterate() create Fibonacci?
Yes — it's one of its most common interview examples.
Q5Which method generates random numbers?
Stream.generate(Math::random).
#Practice Problems
Using range() / rangeClosed():
- Print numbers 1–100.
- Print even numbers from 1–50.
- Print odd numbers from 1–50.
- Print squares of numbers 1–10.
- Find the sum of 1–100.
- Count numbers divisible by 3.
- Print multiples of 7.
- Find the maximum square.
- Convert the range to
List<Integer>. - Print numbers in reverse (hint:
boxed(),sorted(Comparator.reverseOrder())).
Using iterate():
- Generate the first 20 natural numbers.
- Generate the first 15 even numbers.
- Generate the first 10 multiples of 3.
- Generate powers of 2.
- Generate Fibonacci numbers.
Using generate():
- Generate 10 random numbers.
- Generate 5 UUIDs.
- Generate 10
"Java"strings. - Generate 5 timestamps.
- Generate random boolean values.
5+ Years Interview Challenge
Generate the next 30 business days (Monday to Friday only), starting from today.
List<LocalDate> businessDays = Stream.iterate(LocalDate.now(), date -> date.plusDays(1))
.filter(date -> date.getDayOfWeek() != DayOfWeek.SATURDAY
&& date.getDayOfWeek() != DayOfWeek.SUNDAY)
.limit(30)
.toList();This demonstrates iterate(), filter(), limit() and the Java Time API. Because streams are lazy, the infinite iterate() is safe here — limit(30) stops it once 30 business days have passed the filter.
#Senior Java Tips
1. Prefer range() for numeric sequences
Instead of Stream.iterate(1, n -> n + 1).limit(100), use IntStream.rangeClosed(1, 100). It's simpler, clearer and more efficient (no boxing).
2. Be careful with infinite streams
Both iterate() and generate() can produce infinite streams. Always ask yourself: "How does this stream stop?" Usually the answer is limit() (or the Java 9 iterate() overload).
3. Choose the right generator
| Need | Use |
|---|---|
| Numeric ranges | range() / rangeClosed() |
| Sequential values | iterate() |
| Independent values | generate() |
#Chapter Summary
range()(end exclusive) vsrangeClosed()(end inclusive)iterate()— each value from the previous onegenerate()— independent values from aSupplier- Infinite streams need
limit() - Fibonacci with an
int[]pair - Java 9's three-argument
iterate()