← Back to Advanced Java Course | Chapter 3: Functional Programming | Lesson 3 of 6

Java Stream API

What is a Stream?

A Stream represents a pipeline of computational steps applied to a sequence of elements. It lets you process a collection's data in a declarative, functional style, describing what transformation you want rather than writing an explicit loop, and it never modifies the underlying data source.

Example: What is a Stream?

java
import java.util.*;
public class Main {
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5);
		long count = nums.stream().count(); // declarative, no explicit loop
		System.out.println(count);
	}
}

Filter and Map

The filter() operation selects only the elements that match a given condition, discarding the rest from the pipeline. The map() operation instead transforms every element in the stream into a new value, one-for-one, without changing how many elements are present.

Example: Filter and Map

java
import java.util.*;
import java.util.stream.*;
public class Main {
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);
		List<Integer> result = nums.stream()
			.filter(n -> n % 2 == 0)
			.map(n -> n * n)
			.collect(Collectors.toList());
		System.out.println(result);
	}
}

Terminal Operations - Collect

Terminal operations are what actually trigger a stream pipeline to execute, since intermediate operations like filter() and map() are lazy and do nothing until a terminal operation is called. The collect() terminal operation gathers the pipeline's final results back into a concrete container, such as a List or Set.

Example: Terminal Operations - Collect

java
import java.util.*;
import java.util.stream.*;
public class Main {
	public static void main(String[] args) {
		List<String> names = List.of("Riya", "Aman", "Zoya");
		List<String> upper = names.stream()
			.map(String::toUpperCase)
			.collect(Collectors.toList()); // triggers the pipeline
		System.out.println(upper);
	}
}

Reduction and Matching

You can combine every element in a stream down into a single value using reduce(), for example to sum a list of numbers or find a maximum. You can also check whether elements satisfy a condition using short-circuiting matchers like anyMatch(), allMatch(), or noneMatch(), which stop scanning as soon as the answer is determined.

Example: Reduction and Matching

java
import java.util.*;
public class Main {
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5);
		int sum = nums.stream().reduce(0, Integer::sum);
		boolean anyEven = nums.stream().anyMatch(n -> n % 2 == 0);
		System.out.println(sum + " " + anyEven);
	}
}

Parallel Streams

You can execute a stream's operations in parallel across multiple CPU cores simply by calling parallelStream() instead of stream(). Make sure any operations you chain onto it are stateless and free of shared mutable state, since parallel execution can otherwise introduce hard-to-debug data races.

Example: Parallel Streams

java
import java.util.*;
public class Main {
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5);
		int sum = nums.parallelStream()
			.mapToInt(Integer::intValue)
			.sum();
		System.out.println(sum);
	}
}
🔒

Chapter Quiz — Complete all 6 topics to unlock

0/6 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.