Terminal Operations
Terminal operations are situated at the very end of a stream pipeline. They consume the elements of the stream to produce a final result, such as a single value, a collection, or simply an execution of an action. The moment a terminal operation is invoked, the entire pipeline of intermediate operations executes simultaneously, and the stream is subsequently closed.
1. Output: forEach
Performs a specified action for each element of the stream. It is very frequently used for debugging and printing to the console.
List<String> members = Arrays.asList("Alice", "Bob", "Charlie");
members.stream().forEach(System.out::println);
2. Matching and Condition Checking: allMatch, anyMatch, noneMatch
Evaluates whether the elements in the stream meet certain conditions, returning a Boolean value.
allMatch(Predicate): Returns true if all elements match the condition.anyMatch(Predicate): Returns true if any single element matches the condition.noneMatch(Predicate): Returns true if no elements match the condition.
List<Integer> scores = Arrays.asList(85, 90, 78, 92);
boolean hasFail = scores.stream().anyMatch(score -> score < 80); // true (78 exists)
boolean isAllPass = scores.stream().allMatch(score -> score >= 80); // false
3. Statistics and Accumulation: count, sum, reduce
count(), sum(), max(), min(), average(): Calculates basic statistical data. (Methods likesum()are provided by primitive streams likeIntStream.)reduce(): Repeatedly combines the elements of the stream into a single summary result using an accumulator function.
int[] numbers = {1, 2, 3, 4, 5};
int sum = Arrays.stream(numbers).sum(); // 15
long count = Arrays.stream(numbers).count(); // 5
// Accumulating a product using reduce
int multiplied = Arrays.stream(numbers)
.reduce(1, (a, b) -> a * b); // 1*1*2*3*4*5 = 120
4. Collecting Results: collect
One of the most widely used terminal operations. It gathers the elements of the stream and repackages them into a collection structure like a List, Set, Map, or even concatenates them into a single string. It takes static methods from the Collectors class as arguments.
List<String> items = Arrays.asList("Apple", "Banana", "Cherry");
// 1. Collect elements into a List
List<String> upperItems = items.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
// 2. Join elements into a single String
String resultText = items.stream()
.collect(Collectors.joining(", "));
// "Apple, Banana, Cherry"
Choosing and utilizing the correct terminal operation concludes the process, making it a critical aspect of mastering Java's data pipeline programming.