Java Streams
advancedPart of Advanced Java
Theory
The Streams API (introduced in Java 8) enables functional-style operations on sequences of data. A stream represents a pipeline of operations.
Stream Pipeline
A stream pipeline has three stages: source, intermediate operations, and terminal operation.
list.stream() // Source
.filter(n -> n > 5) // Intermediate (lazy)
.map(n -> n * 2) // Intermediate (lazy)
.forEach(System.out::println); // Terminal (eager)Intermediate operations return a new stream and are lazy — they don't execute until a terminal operation is invoked.
map / filter / reduce
map— transforms each element (e.g.,String::length)filter— selects elements matching a predicatereduce— aggregates elements into a single result
int sum = numbers.stream()
.filter(n -> n > 0)
.reduce(0, Integer::sum);Collectors
Collectors accumulate stream elements into collections or other data structures:
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
String joined = stream.collect(Collectors.joining(", "));
Map<Integer, List<String>> grouped = stream
.collect(Collectors.groupingBy(String::length));Optional
Optional<T> is a container that may or may not contain a value. It helps avoid NullPointerException:
Optional<String> opt = Optional.ofNullable(getName());
opt.ifPresent(System.out::println);
String result = opt.orElse("default");Parallel Streams
Call .parallelStream() or .parallel() to process elements concurrently. Use when operations are independent and the dataset is large.
Practical Examples
Exercises
Process Student Scores
Given a list of student scores (integers), use streams to: filter passing scores (>= 60), double them, sort descending, and collect to a list. Also compute the average of passing scores using Optional.
Expected Output:
Passing doubled: [184, 176, 156, 142, 126]\nAverage: 78.4