Java Stream API Tutorial: Definitions, Operations, and Code Examples
This tutorial provides a comprehensive overview of Java's Stream API, explaining its definition, how to obtain streams, the structure of stream processing, and detailed examples of common intermediate and terminal operations with complete code snippets.
This article is a detailed tutorial on Java's Stream API, covering its definition, how to obtain streams, the composition of stream processing, and a thorough list of common intermediate and terminal operations with code examples.
Definition of Stream
In Java, a Stream is a component that can internally iterate over its elements, meaning the Stream handles the iteration itself. This differs from using a Collection's iterator or the Iterable interface's forEach method, where the developer must manage iteration.
Stream Processing
Processor methods (or listeners) can be attached to a Stream. When the Stream iterates internally, each element is passed to these processors, which are invoked for every element, forming a processing chain.
Multiple processor methods can be chained: the output of one processor becomes the input for the next. Processors may return the same element or a transformed one, depending on their purpose.
How to Obtain a Stream
The most common way to get a Stream is from a Collection. Example:
List
items = new ArrayList<>();
items.add("one");
items.add("two");
items.add("three");
Stream
stream = items.stream();All collection objects implement the Collection interface, which defines the stream() method.
Composition of Stream Processing
A Stream processing pipeline consists of a source, zero or more intermediate operations, and a terminal operation.
Source: the origin of elements, such as a Collection.
Intermediate operations: added processors that return a new Stream; they are lazily executed.
Terminal operation: triggers internal iteration, applies all processors, and returns a result.
Intermediate Operations
map
map() transforms each element to another object, e.g., converting strings to uppercase.
List
list = new ArrayList<>();
Stream
stream = list.stream();
Stream
streamMapped = stream.map(value -> value.toUpperCase());filter
filter() removes elements that do not satisfy a given Predicate .
Stream
longStringsStream = stream.filter(value -> value.length() >= 3);flatMap
flatMap() maps each element to a Stream and then flattens the resulting Streams into a single Stream.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamFlatMapExamples {
public static void main(String[] args) {
List
stringList = new ArrayList<>();
stringList.add("One flew over the cuckoo's nest");
stringList.add("To kill a mockingbird");
stringList.add("Gone with the wind");
Stream
stream = stringList.stream();
stream.flatMap(value -> {
String[] split = value.split(" ");
return Arrays.asList(split).stream();
}).forEach(value -> System.out.println(value));
}
}distinct
distinct() returns a new Stream containing only unique elements, removing duplicates.
List
stringList = new ArrayList<>();
stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");
Stream
stream = stringList.stream();
List
distinctStrings = stream.distinct().collect(Collectors.toList());
System.out.println(distinctStrings); // [one, two, three]limit
limit(n) truncates the Stream to contain at most n elements.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class StreamLimitExample {
public static void main(String[] args) {
List
stringList = new ArrayList<>();
stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");
Stream
stream = stringList.stream();
stream.limit(2).forEach(element -> System.out.println(element));
}
}peek
peek() is a debugging intermediate operation that consumes each element with a Consumer without modifying the Stream.
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());Terminal Operations
Terminal operations start internal iteration and produce a final result.
anyMatch
anyMatch(predicate) returns true if any element satisfies the predicate.
boolean anyMatch = stream.anyMatch(value -> value.startsWith("One"));
System.out.println(anyMatch);allMatch
allMatch(predicate) returns true only if all elements satisfy the predicate.
boolean allMatch = stream.allMatch(value -> value.startsWith("One"));
System.out.println(allMatch);noneMatch
noneMatch(predicate) returns true if no elements satisfy the predicate.
boolean noneMatch = stream.noneMatch(element -> "xyz".equals(element));
System.out.println("noneMatch = " + noneMatch);collect
collect() gathers the Stream's elements into a collection or another container.
List
stringsAsUppercaseList = stream
.map(value -> value.toUpperCase())
.collect(Collectors.toList());
System.out.println(stringsAsUppercaseList);count
count() returns the number of elements in the Stream.
long count = stream.flatMap(value -> {
String[] split = value.split(" ");
return Arrays.asList(split).stream();
}).count();
System.out.println("count = " + count);findAny
findAny() returns an Optional containing any element of the Stream.
Optional
anyElement = stream.findAny();
if (anyElement.isPresent()) {
System.out.println(anyElement.get());
} else {
System.out.println("not found");
}findFirst
findFirst() returns an Optional containing the first element of the Stream.
Optional
firstElement = stream.findFirst();
if (firstElement.isPresent()) {
System.out.println(firstElement.get());
} else {
System.out.println("not found");
}forEach
forEach() performs an action for each element; it returns void .
stream.forEach(System.out::println);min / max
min(comparator) and max(comparator) return the smallest or largest element according to the provided Comparator , wrapped in an Optional .
Optional
min = stream.min(String::compareTo);
Optional
max = stream.max(String::compareTo);reduce
reduce() aggregates Stream elements into a single result using a binary operator.
Optional
reduced = stream.reduce((value, combined) -> combined + " + " + value);
reduced.ifPresent(System.out::println);toArray
toArray() converts the Stream into an array of Object , with an overloaded version allowing a typed array.
Object[] objects = stream.toArray();
String[] strArray = stream.toArray(String[]::new);Stream Concatenation
The static method Stream.concat(stream1, stream2) merges two Streams into one.
Stream
concatStream = Stream.concat(stream1, stream2);
List
combined = concatStream.collect(Collectors.toList());
System.out.println(combined);Creating Streams from Arrays
The static method Stream.of(...) can create a Stream from individual objects, multiple objects, or an array.
Stream
stream1 = Stream.of("one", "two", "three");
Stream
stream2 = Stream.of(new String[]{"one", "two"});
System.out.println(stream1.count()); // 3
System.out.println(stream2.count()); // 2In summary, this article enumerates the main intermediate and terminal operations of Java Streams, providing simple examples to illustrate their effects. A follow‑up article will demonstrate more complex, high‑frequency Stream usages in real projects.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.