Syntax
collection.stream().filter(...).map(...).collect(...)Examples
Creating a Stream and forEach
Getting a stream from a collection and processing each element.
import java.util.List;
List<String> names = List.of("Fola", "Zain", "Jamal");
names.stream()
.forEach(name -> System.out.println("Hello, " + name));filter(): Keeping Matching Elements
Building a new stream containing only elements that satisfy a condition.
import java.util.List;
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.toList();
System.out.println(evens); // [2, 4, 6, 8, 10]map(): Transforming Elements
Producing a new stream by applying a transformation to every element.
import java.util.List;
List<String> names = List.of("fola", "zain", "jamal");
List<String> capitalized = names.stream()
.map(String::toUpperCase)
.toList();
System.out.println(capitalized); // [FOLA, ZAIN, JAMAL]Chaining Multiple Operations
The real power of streams: combining filter, map, and other operations into a readable pipeline.
import java.util.List;
List<String> words = List.of("apple", "hi", "banana", "ok", "cherry");
List<String> result = words.stream()
.filter(w -> w.length() > 2)
.map(String::toUpperCase)
.sorted()
.toList();
System.out.println(result); // [APPLE, BANANA, CHERRY]Best practices
- Chain intermediate operations (filter, map, sorted) in the order that reduces the data as early as possible for better performance
- Remember streams are lazy - intermediate operations do nothing until a terminal operation (like collect or forEach) is called
- Use method references (String::toUpperCase) instead of an equivalent lambda (s -> s.toUpperCase()) when the lambda just calls one existing method
- Remember a stream can only be consumed once - calling a terminal operation twice on the same stream throws an IllegalStateException
At a glance
- Purpose
- General-purpose application development
- File extension
- .java
- Runs in
- Java Virtual Machine
- Usually used with
- JDK and Java libraries
Specifications & further reading
Related Java documentation
Lambda Expressions
A lambda expression is a compact way to represent an anonymous function - a block of code that can be passed around as a value. Lambdas work with functional interfaces (interfaces with exactly one abstract method), letting you replace a full anonymous class implementation with a short, focused expression. Lambdas are the foundation that makes Java's Stream API and functional-style programming possible.Stream Terminal Operations
Terminal operations are what actually trigger a stream pipeline to execute and produce a final result, consuming the stream in the process - after a terminal operation runs, the stream cannot be reused. Common terminal operations include reduce() for combining elements into a single value, count(), sum-style operations for numeric streams, anyMatch()/allMatch() for boolean checks, and findFirst() for retrieving a single element.Collectors
Collectors, used with the stream terminal operation collect(), provide ready-made ways to accumulate stream elements into a final result - a List, Set, Map, a joined String, or grouped/partitioned data. The java.util.stream.Collectors class offers factory methods like toList(), joining(), groupingBy(), and counting() that cover the vast majority of real-world aggregation needs.Optional
Optional<T> is a container object that may or may not hold a non-null value, designed to make the possibility of 'no result' explicit in a method's return type, reducing NullPointerExceptions. Rather than returning null and hoping callers remember to check for it, a method returning Optional<T> signals clearly that a value might be absent, and provides safe methods like isPresent(), ifPresent(), and orElse() for handling both cases.
A lambda expression is a compact way to represent an anonymous function - a block of code that can be passed around as a value. Lambdas work with functional interfaces (interfaces with exactly one abstract method), letting you replace a full anonymous class implementation with a short, focused expression. Lambdas are the foundation that makes Java's Stream API and functional-style programming possible.Stream Terminal Operations
Terminal operations are what actually trigger a stream pipeline to execute and produce a final result, consuming the stream in the process - after a terminal operation runs, the stream cannot be reused. Common terminal operations include reduce() for combining elements into a single value, count(), sum-style operations for numeric streams, anyMatch()/allMatch() for boolean checks, and findFirst() for retrieving a single element.Collectors
Collectors, used with the stream terminal operation collect(), provide ready-made ways to accumulate stream elements into a final result - a List, Set, Map, a joined String, or grouped/partitioned data. The java.util.stream.Collectors class offers factory methods like toList(), joining(), groupingBy(), and counting() that cover the vast majority of real-world aggregation needs.Optional
Optional<T> is a container object that may or may not hold a non-null value, designed to make the possibility of 'no result' explicit in a method's return type, reducing NullPointerExceptions. Rather than returning null and hoping callers remember to check for it, a method returning Optional<T> signals clearly that a value might be absent, and provides safe methods like isPresent(), ifPresent(), and orElse() for handling both cases.