一、告別 for 循環!
傳統痛點:
Java 8 之前,集合操作離不開冗長的 for
循環和匿名類。例如,過濾列表中的偶數:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evens = new ArrayList<>();
for (Integer num : list) {if (num % 2 == 0) evens.add(num);
}
Stream 救場:
一行代碼搞定:
List<Integer> evens = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
核心優勢:
- 簡潔:鏈式調用替代復雜循環。
- 高效:惰性計算(Lazy Evaluation),按需執行。
- 并行:一鍵切換并行處理,提升性能。
二、Stream 三大核心操作:過濾、映射、歸約
1. 過濾(filter):篩出想要的元素
作用:只保留符合條件的元素。
語法:filter(Predicate<T> predicate)
示例:篩選長度超過3的字符串
List<String> languages = Arrays.asList("Java", "Python", "C++", "Go");
List<String> filtered = languages.stream().filter(s -> s.length() > 3).collect(Collectors.toList());
// 結果: ["Java", "Python"]
底層邏輯:遍歷流中每個元素,保留 predicate.test(element)
為 true
的元素。
注意:filter
是中間操作,返回新流,需配合終端操作(如 collect
)才能執行。
2. 映射(map):元素轉換
作用:將元素轉換為另一種形式。
語法:map(Function<? super T, ? extends R> mapper)
示例:將字符串轉為大寫
List<String> upperCase = languages.stream().map(String::toUpperCase).collect(Collectors.toList());
// 結果: ["JAVA", "PYTHON", "C++", "GO"]
進階玩法:
- 扁平化嵌套集合:用?
flatMap
?展開多層結構List<List<String>> nested = Arrays.asList(Arrays.asList("a", "b"),Arrays.asList("c", "d")); List<String> flat = nested.stream().flatMap(Collection::stream).collect(Collectors.toList()); // 結果: ["a", "b", "c", "d"]
3. 歸約(reduce):聚合數值,合二為一
作用:將元素合并為一個值(如求和、拼接字符串)。
語法:reduce(T identity, BinaryOperator<T> accumulator)
示例:計算整數列表的總和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
int sum = numbers.stream().reduce(0, Integer::sum);
// 結果: 10
魔法細節:
identity
?是初始值(如求和時設為?0
)。accumulator
?定義如何合并元素(如?a + b
)。
三、實戰:從新手到封神的 3 個場景
場景1:統計文本中單詞頻率
String text = "java stream api is powerful and easy to use";
Map<String, Long> wordCount = Arrays.stream(text.split(" ")).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
// 結果: {java=1, stream=1, api=1, ...}
關鍵點:
split(" ")
?分割字符串為流。groupingBy
?按單詞分組,counting
?統計次數。
場景2:并行處理大數據(真香警告)
List<Integer> largeList = IntStream.range(0, 1000000).parallel() // 切換并行流.filter(x -> x % 2 == 0).boxed().collect(Collectors.toList());
System.out.println(largeList );
效率對比:
- 串行流處理100萬數據:約500ms。
- 并行流處理:約100ms(8核CPU)。
場景3:多級排序(薪資+年齡)
class Employee {String name;int salary;int age;// constructor & getters
}List<Employee> sorted = employees.stream().sorted(Comparator.comparing(Employee::getSalary).thenComparing(Employee::getAge)).collect(Collectors.toList());
System.out.println(sorted);
技巧:鏈式 Comparator
實現多條件排序。
四、避坑指南:新手常踩的雷區
-
流只能使用一次
Stream<Integer> stream = numbers.stream(); stream.forEach(System.out::println); // 正常 stream.forEach(System.out::println); // 報錯!流已關閉
-
避免修改外部變量
int count = 0; numbers.stream().forEach(n -> count++); // 錯誤!并行流下可能出錯
-
并行流未必更快
- 小數據量:串行更優(省去線程切換開銷)。
- 大數據量+復雜操作:并行提速顯著。
五、總結:Stream API 的江湖地位
操作 | 傳統方式 | Stream 寫法 | 爽點 |
---|---|---|---|
過濾偶數 | for ?+?if | filter(x -> x%2==0) | 代碼量減半 |
字符串轉大寫 | 循環+toUpperCase | map(String::toUpperCase) | 一行搞定 |
統計總數 | for ?累加 | reduce(0, Integer::sum) | 函數式編程優雅度拉滿 |