前言
Java 8 引入了 Stream API,它是一種用于處理集合(Collection)數據的強大工具。Stream 不是數據結構,而是對數據源進行操作的一種方式,支持聲明式、函數式的操作,如過濾、映射、排序等。
Stream 操作分為中間操作和終端操作:
- 中間操作(Intermediate operations):返回一個 Stream,可以鏈式調用。
- 終端操作(Terminal operations):觸發實際計算,返回非 Stream 類型的結果。
獲取 Stream 的方式
常見的創建 Stream 的方法如下:
// 從集合創建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();// 從數組創建
int[] arr = {1, 2, 3};
IntStream intStream = Arrays.stream(arr);// 使用 Stream.of 創建
Stream<String> stream = Stream.of("a", "b", "c");// 無限流(generate / iterate)
Stream<Integer> infiniteStream = Stream.generate(() -> 1);
Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2);
Stream 的常用操作
filter
用于過濾符合條件的數據:
List<String> filtered = list.stream().filter(s -> s.startsWith("J")).toList();
map
將每個元素映射成另一個對象:
List<String> upperCase = list.stream().map(String::toUpperCase).toList();
sorted
對流中的元素進行排序:
List<String> sorted = list.stream().sorted().toList();
也可以自定義排序規則
.sorted((s1, s2) -> s2.compareTo(s1))
或者使用 Comparator:
.sorted(Comparator.reverseOrder())
limit / skip
限制流的大小或跳過前 N 個元素:
List<String> limited = list.stream().limit(2).toList();List<String> skipped = list.stream().skip(2).toList();
distinct
去重,基于 equals() 方法判斷重復項:
List<String> unique = list.stream().distinct().toList();
forEach
遍歷流中的每個元素:
list.stream().forEach(System.out::println);
collect
收集流的結果到容器中,常配合 Collectors 使用:
List<String> filteredList = list.stream().filter(s -> s.length() > 3).collect(Collectors.toList());String joined = list.stream().collect(Collectors.joining(", "));
reduce
歸約操作,合并流中的元素為一個結果:
Optional<String> reduced = list.stream().reduce((s1, s2) -> s1 + "-" + s2);
也可以提供初始值:
String result = list.stream().reduce("start", (acc, s) -> acc + "-" + s);
并行流(Parallel Stream)
使用并行流可以提高大數據量下的處理效率:
List<String> parallelResult = list.parallelStream().filter(s -> s.startsWith("A")).toList();
需要注意線程安全問題和是否適合并行處理。
注意事項
- Stream 只能被消費一次,再次使用會拋出異常。
- 中間操作是惰性求值的,只有遇到終端操作才會真正執行。
- 避免在流中修改外部變量,容易引發并發問題。
- 適當使用并行流,不是所有情況都適用。
- 注意空指針異常,尤其是在處理集合時。
總結
Stream API 極大地簡化了對集合的操作,使得代碼更簡潔、可讀性更高。通過鏈式調用,我們可以清晰地表達數據處理邏輯。但也要注意其性能特性和使用場景,合理選擇是否使用 Stream 或傳統循環。