Appearance
Other Operations
We categorize the operations provided by Stream into two types: transformation operations and aggregation operations. Besides the commonly introduced operations, Stream also offers a series of very useful methods.
Sorting
Sorting the elements of a Stream is very straightforward; simply call the sorted() method:
java
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
List<String> list = List.of("Orange", "apple", "Banana")
.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(list);
}
}This method requires that each element of the Stream implements the Comparable interface. If you want to customize the sorting, you can pass a specific Comparator:
java
List<String> list = List.of("Orange", "apple", "Banana")
.stream()
.sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());Note: sorted() is merely a transformation operation; it returns a new Stream.
Distinct
To remove duplicate elements from a Stream, there is no need to first convert it to a Set; you can directly use distinct():
java
List.of("A", "B", "A", "C", "B", "D")
.stream()
.distinct()
.collect(Collectors.toList()); // [A, B, C, D]Skipping and Limiting
Skipping and limiting operations are often used to convert an infinite Stream into a finite one. skip() is used to skip the first N elements of the current Stream, and limit() is used to take at most the first N elements of the current Stream:
java
List.of("A", "B", "C", "D", "E", "F")
.stream()
.skip(2) // Skip A, B
.limit(3) // Take C, D, E
.collect(Collectors.toList()); // [C, D, E]Skipping and limiting operations are also transformation operations and will return a new Stream.
Merging
To merge two Streams into one, you can use the static method Stream.concat():
java
Stream<String> s1 = List.of("A", "B", "C").stream();
Stream<String> s2 = List.of("D", "E").stream();
// Merge:
Stream<String> s = Stream.concat(s1, s2);
System.out.println(s.collect(Collectors.toList())); // [A, B, C, D, E]flatMap
If the elements of a Stream are collections:
java
Stream<List<Integer>> s = Stream.of(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5, 6),
Arrays.asList(7, 8, 9));and we want to convert the above Stream into a Stream<Integer>, we can use flatMap():
java
Stream<Integer> i = s.flatMap(list -> list.stream());Thus, flatMap() refers to mapping each element of the Stream (here, a List) to a Stream, and then merging them into a new Stream:
┌─────────────┬─────────────┬─────────────┐
│┌───┬───┬───┐│┌───┬───┬───┐│┌───┬───┬───┐│
││ 1 │ 2 │ 3 │││ 4 │ 5 │ 6 │││ 7 │ 8 │ 9 ││
│└───┴───┴───┘│└───┴───┴───┘│└───┴───┴───┘│
└─────────────┴─────────────┴─────────────┘
│
│flatMap(List -> Stream)
│
│
▼
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┘Parallel Processing
By default, processing the elements of a Stream is single-threaded, meaning elements are processed one by one. However, often we want to process Stream elements in parallel, especially when dealing with a large number of elements, as parallel processing can significantly speed up the processing.
Converting a regular Stream into a parallel Stream is very simple; just use parallel():
java
Stream<String> s = ...
String[] result = s.parallel() // Convert to a parallel Stream
.sorted() // Can perform parallel sorting
.toArray(String[]::new);Once converted using parallel(), the Stream will perform subsequent operations in parallel whenever possible. We do not need to write any multi-threaded code to enjoy the execution efficiency improvements brought by parallel processing.
Other Aggregation Methods
Besides reduce() and collect(), Stream provides some other commonly used aggregation methods:
count(): Returns the number of elements.max(Comparator<? super T> cp): Finds the maximum element.min(Comparator<? super T> cp): Finds the minimum element.
For IntStream, LongStream, and DoubleStream, additional aggregation methods are provided:
sum(): Sums all elements.average(): Calculates the average of all elements.
There are also methods to test whether Stream elements satisfy certain conditions:
boolean allMatch(Predicate<? super T>): Tests whether all elements satisfy the condition.boolean anyMatch(Predicate<? super T>): Tests whether at least one element satisfies the condition.
The last commonly used method is forEach(), which can iterate over each element of the Stream. We often pass System.out::println to print the elements of the Stream:
java
Stream<String> s = ...
s.forEach(str -> {
System.out.println("Hello, " + str);
});Summary
Common operations provided by Stream include:
- Transformation Operations:
map(),filter(),sorted(),distinct(); - Merging Operations:
concat(),flatMap(); - Parallel Processing:
parallel(); - Aggregation Operations:
reduce(),collect(),count(),max(),min(),sum(),average(); - Other Operations:
allMatch(),anyMatch(),forEach().