Java Stream流從入門到精通(最新整理)
Stream流,這是一個非常重要的里程碑。它代表了從“命令式編程”向“聲明式編程”風格的轉變,剛開始不理解是非常正常的。
一、Stream是做什么的?—— “流水線”的比喻
你可以把Stream想象成一條工廠里的流水線。
- 數(shù)據(jù)源(集合、數(shù)組等):就像是待加工的原材料,被放在流水線的開頭。
- 零個或多個“中間操作” (Intermediate operations):就像是流水線上的一道道加工工序,比如篩選、轉換、排序等。這些工序不會立刻執(zhí)行,只是被定義出來。
- 一個“終結操作” (Terminal operation):就像是流水線的最后一道工序,比如打包、裝箱。只有到了這一步,整個流水線才會被啟動,所有原材料才會依次經(jīng)過各個加工工序,最終產(chǎn)生結果。
Stream的核心思想是:你只需告訴它“做什么”(What),而不是“怎么做”(How)。
- 傳統(tǒng)循環(huán)(命令式):你寫一個
for循環(huán),自己處理迭代、定義臨時變量、寫if條件判斷。你是在指導計算機每一步該怎么執(zhí)行。 - Stream流(聲明式):你直接說“幫我過濾出大于5的數(shù),然后轉換成字符串,最后排序并收集到一個列表里”。你只關心結果,而不關心內(nèi)部是如何遍歷和處理的。
舉個例子:有一個數(shù)字列表,找出所有偶數(shù),然后求它們的平方,最后收集到一個新列表里。
傳統(tǒng)方式(命令式):
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> evenSquares = new ArrayList<>();
for (Integer number : numbers) {
if (number % 2 == 0) { // 自己寫if判斷
int square = number * number; // 自己計算平方
evenSquares.add(square); // 自己添加到新集合
}
}Stream方式(聲明式):
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> evenSquares = numbers.stream() // 1. 獲取流
.filter(n -> n % 2 == 0) // 2. “工序”一:過濾偶數(shù)
.map(n -> n * n) // 3. “工序”二:映射為平方
.collect(Collectors.toList()); // 4. “啟動”流水線:收集結果你看,Stream的代碼更簡潔、更易讀,它的每一步操作都像在描述業(yè)務邏輯本身。
二、是任何類型都可以使用Stream嗎?
不是任何類型本身都能用,但任何類型的【集合】或【數(shù)組】幾乎都可以轉換成Stream來處理。
Stream流本身是一個通用工具,但它不能直接作用于單個對象(比如你有一個String name = "Alice",你不能name.stream())。它的操作對象是數(shù)據(jù)序列。
數(shù)據(jù)源主要來自以下幾個方面:
從集合(Collection)來(最常見):
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> streamFromList = list.stream();
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Stream<Integer> streamFromSet = set.stream();所有Collection的實現(xiàn)類(List, Set, Queue等)都有.stream()方法。
從數(shù)組來:
int[] numbers = {1, 2, 3, 4, 5};
IntStream streamFromArray = Arrays.stream(numbers); // 注意是IntStream使用Arrays.stream(array)靜態(tài)方法。
使用Stream類的靜態(tài)方法:
Stream<String> streamOfValues = Stream.of("Java", "Python", "C++");
// 創(chuàng)建一個無限的奇數(shù)流:1, 3, 5, 7...
Stream<Integer> infiniteStream = Stream.iterate(1, n -> n + 2);Stream.of(T... values): 直接用值創(chuàng)建流。
Stream.iterate() 和 Stream.generate(): 創(chuàng)建無限流。
從文件等I/O資源來(比如Files.lines()):
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
lines.forEach(System.out::println);
}特別注意:基本類型
直接操作基本類型(int, long, double)為了避免裝箱拆箱的性能損耗,Java提供了特化的流:IntStream, LongStream, DoubleStream。
它們有額外的方法,如sum(), average(), range()等。
所以,結論是:你需要有一個數(shù)據(jù)序列(通常是集合或數(shù)組),然后就可以把它變成Stream來使用。
三、Stream的操作分類:中間操作 vs. 終結操作
這是理解Stream執(zhí)行機制的關鍵。Stream的操作分為兩大類:
| 類型 | 特點 | 常見方法 | 返回值 |
|---|---|---|---|
| 中間操作 | 懶惰的 (Lazy) | filter(), map(), sorted(), distinct(), limit() | 返回一個新的Stream |
| 不會立即執(zhí)行,只是被記錄下來 | flatMap(), peek() | ||
| 終結操作 | 積極的 (Eager) | collect(), forEach(), count() | 返回一個非Stream的結果 |
| 會觸發(fā)整個流水線的實際執(zhí)行 | findFirst(), anyMatch(), reduce(), min()/max() | (如void, List, Optional, int等) |
執(zhí)行原理:只有在調用終結操作時,所有中間操作才會組合成一個“流水線方案”,然后數(shù)據(jù)源中的元素會逐個地依次通過整個流水線。這種處理方式稱為“循環(huán)融合”,效率很高,因為它只需要遍歷一次集合。
四、常用的Stream操作(“加工工序”)
filter(Predicate<? super T> predicate)- 過濾- 保留滿足條件的元素。
Predicate是一個返回boolean的函數(shù)。 .filter(s -> s.length() > 3)// 保留長度大于3的字符串
- 保留滿足條件的元素。
map(Function<? super T, ? extends R> mapper)- 映射/轉換- 將元素轉換成另一種形式。
Function是一個轉換函數(shù)。 .map(String::toUpperCase)// 將每個字符串轉為大寫.map(n -> n * 2)// 將每個數(shù)字乘以2
- 將元素轉換成另一種形式。
sorted()/sorted(Comparator<? super T> comparator)- 排序distinct()- 去重limit(long maxSize)- 限制數(shù)量collect(Collector<? super T, A, R> collector)- 收集(最常用的終結操作)- 將流中的元素收集到各種不同的容器中(如List, Set, Map)。
.collect(Collectors.toList()).collect(Collectors.toSet()).collect(Collectors.joining(", "))// 連接成字符串.collect(Collectors.groupingBy(User::getDepartment))// 按部門分組
總結與建議
- Stream是什么:一個用于高效處理數(shù)據(jù)序列(特別是集合)的聲明式API,遵循“流水線”模式。
- 核心優(yōu)勢:代碼簡潔、可讀性強、易于并行化(只需將
.stream()換成.parallelStream())。 - 使用條件:數(shù)據(jù)源需要是集合、數(shù)組等可以生成序列的類型。
- 關鍵機制:操作分為中間操作(懶惰,定義工序)和終結操作(積極,啟動執(zhí)行)。
給你的學習建議:
- 多練習從
List和Array創(chuàng)建流。 - 重點掌握
filter、map和collect這三個最常用的方法。 - 理解每個中間操作都會返回一個新流,但不會觸發(fā)計算。
- 記住,沒有終結操作,整個Stream流水線就什么都不會做。
到此這篇關于Java Stream流:從入門到精通的文章就介紹到這了,更多相關Java Stream流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
淺談Java中Collections.sort對List排序的兩種方法
本文介紹了Java中Collections.sort對List排序的兩種方法以及Comparable 與Comparator區(qū)別,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
SpringBoot啟動后自動執(zhí)行方法的各種方式對比
這篇文章主要為大家詳細介紹了SpringBoot啟動后自動執(zhí)行方法的各種方式和性能對比,文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下2025-04-04
idea中maven使用tomcat7插件運行run報錯Could not start T
這篇文章主要介紹了idea中maven使用tomcat7插件運行run報錯Could not start Tomcat問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-09-09
解讀@ResponseBody與@RequestBody注解的用法
這篇文章主要介紹了Spring MVC中的@ResponseBody和@RequestBody注解的用法,@ResponseBody注解用于將Controller方法的返回對象轉換為指定格式(如JSON)并通過Response響應給客戶端,@RequestBody注解用于讀取HTTP請求的內(nèi)容2024-11-11

