Java Core: Stream API - Creating Streams
The Stream API, introduced in Java 8, provides a functional and declarative way to process collections of data. A core concept is the Stream itself. This document details how to create streams from various sources.
What is a Stream?
A Stream is a sequence of elements supporting sequential and parallel aggregate operations. Key characteristics:
- Not a data structure: It doesn't store data; it operates on a source.
- Functional: Encourages operations like
map,filter,reducewithout side effects. - Lazy: Operations are only performed when a terminal operation is invoked.
- Immutable: Streams themselves are not modified. Operations create new streams.
Ways to Create Streams
Here's a breakdown of common methods for creating streams:
1. From Collections:
The most frequent way to create streams is from existing collections like List, Set, and Map.
Collection.stream(): Creates a sequential stream.Collection.parallelStream(): Creates a parallel stream (for potential performance gains on multi-core processors).
import java.util.List;
import java.util.Arrays;
public class StreamFromCollection {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Sequential stream
names.stream().forEach(System.out::println);
// Parallel stream
names.parallelStream().forEach(System.out::println);
}
}
2. From Arrays:
Similar to collections, you can create streams from arrays.
Arrays.stream(array): Creates a sequential stream from an array.Arrays.stream(array).parallel(): Creates a parallel stream from an array.
import java.util.Arrays;
public class StreamFromArray {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
// Sequential stream
Arrays.stream(numbers).forEach(System.out::println);
// Parallel stream
Arrays.stream(numbers).parallel().forEach(System.out::println);
}
}
3. Using Stream.of():
This static method allows you to create streams from individual elements.
Stream.of(element1, element2, ...): Creates a sequential stream from a variable number of arguments.
import java.util.stream.Stream;
public class StreamOf {
public static void main(String[] args) {
Stream<String> colors = Stream.of("Red", "Green", "Blue");
colors.forEach(System.out::println);
}
}
4. Using Stream.iterate():
Creates an infinite sequential stream by repeatedly applying a function to an initial seed value. Requires a terminal operation to limit the stream.
Stream.iterate(seed, function):seedis the initial value, andfunctiontakes the previous value and returns the next.
import java.util.stream.Stream;
public class StreamIterate {
public static void main(String[] args) {
Stream<Integer> evenNumbers = Stream.iterate(0, n -> n + 2).limit(5);
evenNumbers.forEach(System.out::println); // Output: 0 2 4 6 8
}
}
5. Using Stream.generate():
Creates an infinite sequential stream by repeatedly calling a supplier. Requires a terminal operation to limit the stream.
Stream.generate(supplier):supplierprovides the next element in the stream.
import java.util.stream.Stream;
import java.util.Random;
public class StreamGenerate {
public static void main(String[] args) {
Random random = new Random();
Stream<Integer> randomNumbers = Stream.generate(random::nextInt).limit(5);
randomNumbers.forEach(System.out::println);
}
}
6. From BufferedReader (Java 9+):
Java 9 introduced methods to create streams directly from BufferedReader instances.
BufferedReader.lines(): Creates a stream of lines from the reader.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class StreamFromBufferedReader {
public static void main(String[] args) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader("myFile.txt"))) {
reader.lines().forEach(System.out::println);
}
}
}
7. From IntStream, LongStream, DoubleStream:
These specialized stream types are designed for primitive int, long, and double values, respectively. They offer performance benefits and specific methods for primitive operations. Creation methods are similar to Stream.of(), Stream.iterate(), and Stream.generate().
import java.util.stream.IntStream;
public class PrimitiveStreams {
public static void main(String[] args) {
IntStream intStream = IntStream.range(1, 6); // 1 to 5 (exclusive of 6)
intStream.forEach(System.out::println);
}
}
Choosing the Right Method
- Existing Collections/Arrays: Use
collection.stream()orArrays.stream(). - Fixed Set of Elements: Use
Stream.of(). - Infinite Sequences: Use
Stream.iterate()orStream.generate(), always with a terminal operation and alimit()to prevent infinite loops. - File Input: Use
BufferedReader.lines()(Java 9+). - Primitive Types: Use
IntStream,LongStream, orDoubleStreamfor performance.
Remember to always consider whether a sequential or parallel stream is appropriate for your use case. Parallel streams can improve performance for computationally intensive tasks, but they also introduce overhead. Careful benchmarking is often necessary to determine the optimal approach.