In the last part, we explored the Functional Interfaces — Predicate, Function, Consumer, Supplier and few more — that form the foundation of stream operations.
Now, it’s time to understand how streams are created. After all, before you can map, filter, or collect data, you need a stream source.
What Is a Stream Source?
A Stream in Java doesn’t store data itself. It’s a sequence of elements sourced from:
- Collections
- Arrays
- Static factory methods (Stream.of())
- Functions that generate infinite streams
1. From Collections
The most common way to get a stream is from a Collection (like List, Set, etc.).
Every collection in Java 8 and later comes with two methods:
stream() – creates a sequential stream
parallelStream() – creates a parallel stream for multi-threaded processing
import java.util.*;
public class StreamFromCollection {
public static void main(String[] args) {
List<String> names = Arrays.asList("Arjun", "Bhima", "Karna", "Nakul");
// Sequential Stream
System.out.println("Sequential Stream:");
names.stream()
.filter(name -> name.startsWith("K"))
.forEach(System.out::println);
// Parallel Stream
System.out.println("\nParallel Stream:");
names.parallelStream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
}
OUTPUT
Sequential Stream:
Karna
Parallel Stream:
ARJUN
BHIMA
KARNA
NAKUL
The order in parallel streams may vary depending on threads.
Takeaways:
Use stream() for predictable sequential processing, and parallelStream() when you can benefit from parallelism that is when performance matters over order and thread-safety.
2. From Arrays
The Arrays class provides a convenient stream() method:
import java.util.Arrays;
import java.util.stream.IntStream;
public class StreamFromArray {
public static void main(String[] args) {
String[] fruits = {"Apple", "Banana", "Cherry"};
Arrays.stream(fruits)
.map(String::toUpperCase)
.forEach(System.out::println);
int[] numbers = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(numbers);
intStream.forEach(System.out::println);
}
}
OUTPUT
APPLE
BANANA
CHERRY
1
2
3
4
5
Why use Arrays.stream() instead of Stream.of() for arrays?
Because Stream.of(numbers) would create a stream of one element (the entire array), not a stream of its contents.
3. Using Stream.of()
Stream.of() can be used to create streams directly from values or object arrays.
import java.util.stream.Stream;
public class StreamOfExample {
public static void main(String[] args) {
Stream<String> gods = Stream.of("Indra", "Agni", "Vayu", "Varuna");
gods.forEach(System.out::println);
// Heterogeneous data
Stream<Object> mixed = Stream.of("Hello", 42, true, 3.14);
mixed.forEach(System.out::println);
}
}
OUTPUT
Indra
Agni
Vayu
Varuna
Hello
42
true
3.14
When to use:
Use Stream.of() for small sets of elements or when you want a quick ad-hoc stream.
4. Infinite Streams — iterate() and generate()
Streams can also be infinite, producing values endlessly — unless you limit them using .limit(n).
Stream.iterate()
import java.util.stream.Stream;
public class IterateExample {
public static void main(String[] args) {
Stream.iterate(1, n -> n + 2)
.limit(5)
.forEach(System.out::println);
}
}
OUTPUT
1
3
5
7
9
Explanation:
Stream.iterate(seed, f)
- seed (1) → The initial value of the stream
- f (n -> n + 2) → The function that computes the next element based on the previous one
So, the stream goes like:
1 → 3 → 5 → 7 → 9 → ... (infinite, but we limited it to 5)
Stream.generate()
import java.util.stream.Stream;
import java.util.Random;
public class GenerateExample {
public static void main(String[] args) {
Stream.generate(() -> new Random().nextInt(100))
.limit(5)
.forEach(System.out::println);
}
}
OUTPUT
42
17
83
9
65
Explanation:
Stream.generate(supplier)
- supplier → A function (no input, returns a value) that provides stream elements.
- Here, we’re generating random integers continuously — .limit(5) ensures we only get 5 numbers.
💡 Important: Always use .limit() with iterate() or generate() — otherwise your program will run forever!
Summary
| Source Type | Example | Stream Method | Notes |
|---|---|---|---|
| Collection | list.stream() |
Sequential stream | Most common source |
| Array | Arrays.stream(array) |
Converts array | Works for primitives too |
| Values | Stream.of(…) |
Direct stream | Quick for literals |
| Infinite (iterate) | Stream.iterate(1, n -> n + 1) |
Iterative stream | Takes seed & function |
| Infinite (generate) | Stream.generate(Math::random) |
Supplier stream | Takes supplier only |
What’s Next?
Now that we know how to create streams, in Part 4, we’ll dive into Intermediate Operations —
methods like map(), filter(), sorted() and more that transform your stream data step by step.
🔗 Next Up (Part 4): Intermediate Operations
Top comments (0)