2. Stream
In Java, a Stream is a sequence of elements that can be processed in parallel or sequentially. It is part of the java.util.stream
package and provides a high-level abstraction for performing operations on collections, arrays, or other data sources in a functional
style.
Streams allow for functional-style operations such as filtering, mapping, and reducing on data, and they help avoid the need for
explicit loops. A stream doesn’t store data; it simply conveys elements from a data source, such as a collection, array, or I/O channel,
through a pipeline of computational operations.
3. Key Characteristics of a Stream
1. No Storage: A stream does not store elements. Instead, it operates on data from a source (such as a collection, array, or I/O
channel) and processes them on-demand.
2. Functional in Nature: Streams support functional-style operations. You can chain operations using method calls to process
data in a more declarative manner, avoiding traditional loops and conditionals.
3. Laziness: Most operations on streams are lazy. This means the operations are not executed until a terminal operation is
invoked. This allows for optimizations, such as short-circuiting (stopping early) or parallelism.
4. Possibility of Parallelism: Streams can be processed in parallel with minimal effort by invoking parallelStream() or using the
parallel() method on a stream.
5. Once-Only: A stream can be traversed only once. After it has been consumed or processed (e.g., using a terminal operation
like collect(), forEach(), etc.), it cannot be reused.
4. Stream Creation
Streams can be created from various data sources such as collections, arrays, or
I/O channels.
From a Collection:
List<String> names = Arrays.asList("John", "Jane", "Adam", "Eve");
Stream<String> nameStream = names.stream();
From an Array:
String[] array = {"a", "b", "c", "d"};
Stream<String> arrayStream = Arrays.stream(array);
From a Range of Numbers:
IntStream rangeStream = IntStream.range(1, 10); // 1 to 9
6. Parallel Stream
A stream that processes data elements in parallel using multiple threads, which can improve performance for large datasets.
● Created by invoking the parallelStream() method on a collection, or by calling the parallel() method on a stream.
Example:
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
● Stream<Integer> parallelStream = numbers.parallelStream();
7. Sequential Stream
A stream that processes data elements sequentially in the order they are encountered.
● Created by invoking the stream() method on a collection.
Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
● Stream<Integer> sequentialStream = numbers.stream();
8. Stream Operations
A Stream represents a sequence of elements and supports a variety of operations that can be chained together. There are two main
types of operations in a stream:
Stream operations are classified into two types:
1. Intermediate Operations: These return a new stream and are lazy, meaning they are not executed until a terminal operation
is invoked.
○ Examples: filter(), map(), sorted(), distinct()
○ These operations create a new stream, which can be further processed.
2. Terminal Operations: These trigger the processing of the stream and produce a result or a side-effect. Once a terminal
operation is invoked, the stream is considered consumed and cannot be reused.
○ Examples: collect(), forEach(), reduce(), count()
9. Explanation of Stream Operations
Intermediate operations (e.g., filter(), map(), sorted(), distinct(), peek()):
● filter(): Filters elements based on a condition (e.g., keep numbers greater than 5).
● map(): Transforms elements (e.g., multiplies each element by 2).
● sorted(): Sorts the elements.
● distinct(): Removes duplicates from the stream.
● peek(): Allows you to perform an action on elements while still passing them through the stream, typically used for debugging or
logging.
Terminal operations (e.g., collect(), forEach(), count(), anyMatch(), reduce()):
● collect(): Collects the results into a container (e.g., a List, Set, etc.).
● forEach(): Iterates over elements and performs an action (e.g., printing them).
● count(): Returns the number of elements in the stream.
● anyMatch(): Checks if any element satisfies a given condition.
● reduce(): Combines elements into a single result (e.g., summing up numbers).
10. Example of a Stream Pipeline
A stream pipeline consists of both intermediate and terminal operations.
Here’s an example:
import java.util.*;
import java.util.stream.*;
public class StreamExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Stream pipeline: filter even numbers, multiply them by 2, collect results into a list
List<Integer> result = numbers.stream() // Create stream
.filter(n -> n % 2 == 0) // Intermediate operation: filter even numbers
.map(n -> n * 2) // Intermediate operation: multiply each by 2
.collect(Collectors.toList()); // Terminal operation: collect to a list
System.out.println(result); // Output: [4, 8, 12, 16, 20]
}
}
11. import java.util.*;
import java.util.stream.*;
public class StreamOperationsExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // Creating a list of integers
Stream<Integer> filteredStream = numbers.stream().filter(n -> n > 5); // filter() - filters out numbers gt than 5
Stream<Integer> mappedStream = filteredStream.map(n -> n * 2); // map() - multiplies each number by 2
Stream<Integer> sortedStream = mappedStream.sorted(); // Sort the stream
List<Integer> resultList = sortedStream.collect(Collectors.toList()); // Collect results into a List
System.out.println("Result after applying stream operations: " + resultList);
List<Integer> numbersWithDuplicates = Arrays.asList(1, 1, 2, 2, 3, 3, 4, 5);
numbersWithDuplicates.stream().distinct().forEach(System.out::println); // Remove duplicates
long count = numbers.stream().peek(n -> System.out.println("Processing: " + n)).count(); // count()
System.out.println("Total count: " + count);
boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0); // Check if there are any even numbers
System.out.println("Contains even numbers: " + hasEven);
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b); // combines elements using an associative accumulation
function
sum.ifPresent(s -> System.out.println("Sum of numbers: " + s));
}
}