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

Java Stream API

A stream is a conveyor belt of items where each step can filter, change, or count them, like a factory line. It lets you process data in a clear chain.
Syntax
java
collection.stream()
    .filter(item -> condition)
    .map(item -> expression)
    .collect(Collectors.toList());

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.* so it can be used by its short name
import java.util.*;
// Import java.util.stream.* so it can be used by its short name
import java.util.stream.*;
// Define the class Main
public class Main {
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);
		// Create a stream from the collection to process it step by step
		List<Integer> result = nums.stream()
			.filter(n -> n % 2 == 0)
			.map(n -> n * n)
			.collect(Collectors.toList());
		// Print a line to the console
		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.* so it can be used by its short name
import java.util.*;
// Define the class Main
public class Main {
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5);
		// Create a stream from the collection to process it step by step
		int sum = nums.stream().reduce(0, Integer::sum);
		// Create a stream from the collection to process it step by step
		boolean anyEven = nums.stream().anyMatch(n -> n % 2 == 0);
		// Print a line to the console
		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.* so it can be used by its short name
import java.util.*;
// Define the class Main
public class Main {
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		List<Integer> nums = List.of(1, 2, 3, 4, 5);
		int sum = nums.parallelStream()
			.mapToInt(Integer::intValue)
			.sum();
		// Print a line to the console
		System.out.println(sum);
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Reusing a stream after a terminal operation like count(), which throws an IllegalStateException; create a new stream instead.
  2. Building a pipeline with only filter and map and no terminal operation, so nothing runs because intermediate operations are lazy.
  3. Adding results to a shared ArrayList from a parallel stream's lambda, which is not thread-safe; use collect instead.
🔒

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.