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 Stream
s 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()
.