Creating streams in Java
collection.stream(), Stream.of, Arrays.stream, IntStream.range, iterate, generate.
Stream.of(nums).count() on an array of three numbers returns… 1. Not 3. One. Where did the other numbers go?Many doors into a stream
Pick the factory that matches your data: **list.stream() for collections, Arrays.stream(array) for arrays, and Stream.of(a, b, c)** for a handful of fixed values.
Stream<String> a = List.of("x", "y").stream();
IntStream b = Arrays.stream(new int[]{1, 2});
Stream<Integer> c = Stream.of(1, 2, 3);Number ranges
IntStream.range(1, 5) gives 1, 2, 3, 4 — the end is exclusive, just like i < 5 in a for loop. IntStream.rangeClosed(1, 5) includes the end: 1 to 5.
IntStream.range(1, 5) // 1 2 3 4
IntStream.rangeClosed(1, 5) // 1 2 3 4 5Range check
What does this print?
IntStream.range(2, 5)
.forEach(System.out::print);2345234345
Show the answer
234 — range stops before its end value. Use rangeClosed(2, 5) to get 2345.
Generators: streams without end
**Stream.iterate(seed, next)** applies next again and again, and **Stream.generate(supplier) calls the supplier forever. Both are infinite**, so they need limit or another stopper. Java 9 added **iterate(seed, hasNext, next), which works like a for loop and stops by itself**.
The three-part iterate
What does this print?
List<Integer> r = Stream
.iterate(1, n -> n < 20, n -> n * 2)
.toList();
System.out.println(r);[1, 2, 4, 8, 16][2, 4, 8, 16][1, 2, 4, 8, 16, 32]
Show the answer
[1, 2, 4, 8, 16] — start at 1, continue while n < 20, double each time. 32 fails the test, so it's never emitted.
The int[] that became one element
Stream.of(T...) is generic, and generics can't hold primitives. So an int[] can't spread into separate ints — the whole array becomes one element of a Stream<int[]>. For primitive arrays, use **Arrays.stream(arr)**, which gives an IntStream.
int[] a = {1, 2, 3};
Stream.of(a).count(); // 1: Stream<int[]>
Arrays.stream(a).count(); // 3: IntStreamWhere you'll meet these
IntStream.range replaces index loops in production code and in coding interviews. Stream.generate(UUID::randomUUID).limit(n) builds test data, and the Stream.of(intArray) surprise is a classic bug in code reviews — the count is silently wrong instead of crashing.
Key takeaways
- list.stream() / Arrays.stream(arr) / Stream.of(a, b, c)
- IntStream.range(1, 5) excludes 5; rangeClosed(1, 5) includes it
- Stream.iterate(seed, next) and Stream.generate(supplier) can be infinite
- iterate(seed, hasNext, next) (Java 9) stops by itself
IntStream.range(0, 0) is perfectly legal: it's simply an empty stream, so count() returns 0.
Practice questions
What does this print?
IntStream.rangeClosed(1, 4)
.forEach(System.out::print);- 123
- 1234
- 01234
- 12345
Check your answer
1234. rangeClosed includes both ends, so it yields 1, 2, 3, 4, printed with no separator.
What does this print?
List<Integer> r = Stream
.iterate(1, n -> n < 50, n -> n * 3)
.toList();
System.out.println(r);- [1, 3, 9, 27, 81]
- [3, 9, 27]
- [1, 3, 9, 27]
- [1, 3, 9, 27, 50]
Check your answer
[1, 3, 9, 27]. The three-argument iterate (Java 9) works like a for loop: start at 1, keep going while n < 50, multiply by 3. 81 fails the test, so it stops before it.