Java 8 中的 Stream API,用于處理集合數據

Java 8 引入了 Stream API,使得處理集合數據變得更加簡潔和高效。Stream API 允許開發者以聲明式編程風格操作數據集合,而不是使用傳統的迭代和條件語句。

一、基本概念

1.1 什么是 Stream

Stream 是 Java 8 中的一個新抽象,它允許對集合數據執行各種復雜的操作,例如過濾、映射、規約、收集等。Stream 不存儲數據,而是從集合或其他數據源(如數組、I/O channel 等)中獲取數據并進行操作。

Stream 的主要特點包括:

  • 無存儲:Stream 不存儲數據,只是對數據進行操作。
  • 函數式編程:使用 lambda 表達式進行操作,使代碼更簡潔。
  • 延遲執行:Stream 操作是懶加載的,只有在需要結果時才會執行。
  • 可組合性:多個 Stream 操作可以連成一串操作鏈,形成一系列的轉換。

1.2 Stream 的生命周期

Stream 的操作可以分為三類:

  • :創建 Stream 的數據源,例如集合、數組或 I/O channel。
  • 中間操作:返回新的 Stream 的操作,例如過濾、映射。
  • 終端操作:產生結果或副作用的操作,例如收集、計算。

一個 Stream 的生命周期可以簡單描述為:

  1. 創建 Stream。
  2. 中間操作。
  3. 終端操作。

二、Stream API 的基本操作

2.1 創建 Stream

Stream 可以通過以下幾種方式創建:

  • 從集合
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
  • 從數組
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
  • 從值
Stream<String> stream = Stream.of("a", "b", "c");
  • 從文件
Stream<String> stream = Files.lines(Paths.get("path/to/file.txt"));

2.2 中間操作

中間操作返回一個新的 Stream,它們是延遲執行的,只有在終端操作執行時才會實際進行計算。常用的中間操作包括:

2.2.1 filter

filter 用于對 Stream 中的元素進行過濾,只保留滿足條件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0);
2.2.2 map

map 用于將 Stream 中的每個元素映射到另一個元素。

List<String> words = Arrays.asList("Java", "Stream", "API");
Stream<Integer> wordLengths = words.stream().map(String::length);
2.2.3 flatMap

flatMap 用于將 Stream 中的每個元素映射到一個新的 Stream,并將這些新 Stream 合并成一個 Stream。

List<List<String>> listOfLists = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
Stream<String> flatStream = listOfLists.stream().flatMap(Collection::stream);
2.2.4 distinct

distinct 用于去除 Stream 中的重復元素。

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
Stream<Integer> distinctNumbers = numbers.stream().distinct();
2.2.5 sorted

sorted 用于對 Stream 中的元素進行排序,可以傳遞一個比較器。

List<String> words = Arrays.asList("Java", "Stream", "API");
Stream<String> sortedWords = words.stream().sorted();

2.3 終端操作

終端操作會觸發 Stream 的計算,并生成結果或副作用。常用的終端操作包括:

2.3.1 forEach

forEach 用于對 Stream 中的每個元素執行一個動作。

List<String> words = Arrays.asList("Java", "Stream", "API");
words.stream().forEach(System.out::println);
2.3.2 toArray

toArray 用于將 Stream 中的元素收集到一個數組中。

List<String> words = Arrays.asList("Java", "Stream", "API");
String[] array = words.stream().toArray(String[]::new);
2.3.3 reduce

reduce 用于將 Stream 中的元素通過一個關聯函數組合起來,生成一個值。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum);
2.3.4 collect

collect 用于將 Stream 中的元素收集到一個容器中,例如 List、Set 或 Map。

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());
2.3.5 count

count 用于返回 Stream 中的元素數量。

List<String> words = Arrays.asList("Java", "Stream", "API");
long count = words.stream().count();
2.3.6 findFirstfindAny

findFirst 用于返回 Stream 中的第一個元素(如果存在)。

List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> first = words.stream().findFirst();

findAny 用于返回 Stream 中的任意一個元素(如果存在),常用于并行流。

List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> any = words.stream().findAny();
2.3.7 anyMatchallMatchnoneMatch

這三個操作用于檢查 Stream 中是否有任意、所有或沒有元素滿足指定的條件。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);

三、并行流

Java 8 提供了并行流,可以充分利用多核處理器的優勢。只需調用 parallelStream 方法即可創建一個并行流。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().reduce(0, Integer::sum);

并行流通過將數據分成多個子流,并在不同的 CPU 核心上并行處理這些子流,然后再合并結果,來提高處理速度。需要注意的是,并行流適合于無狀態和無副作用的操作,使用時需小心處理共享變量和同步問題。

四、Stream API 的最佳實踐

4.1 使用 Lambda 表達式

Stream API 通常與 lambda 表達式一起使用,使代碼更加簡潔和易讀。例如:

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(word -> word.toUpperCase()).collect(Collectors.toList());

4.2 避免使用修改狀態的中間操作

Stream 操作應該是無副作用的,即不應修改外部狀態。以下示例展示了一個錯誤的用法:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> results = new ArrayList<>();
numbers.stream().forEach(n -> results.add(n * 2));  // 這樣做是錯誤的

正確的做法是使用終端操作 collect

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> results = numbers.stream().map(n -> n * 2).collect(Collectors.toList());

4.3 利用方法引用

方法引用可以使代碼更加簡潔。例如,使用方法引用替代 lambda 表達式:

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());

4.4 避免使用并行流進行小任務

并行流在處理大量數據或復雜計算時非常高效,但對于小任務,啟動并行計算的開銷可能會大于收益。因此,在數據量較小或計算較簡單的情況下,優先使用順序流。

4.5 避免在終端操作之前調用 findAny

在終端操作之前調用 findAny 會導致流的中間操作鏈被截斷,進而無法正確執行后續的操作。例如:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = numbers.stream().filter(n -> n % 2 == 0).findAny(); // 這樣做會中斷流

應將 findAny 用作終端操作:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = numbers.stream().filter(n -> n % 2 == 0).findAny();

4.6 使用 collect 進行結果收集

collect 是一個強大的終端操作,可以將流中的元素收集到各種容器中。例如,收集到 List:

List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> wordList = words.stream().collect(Collectors.toList());

4.7 使用 Collectors 進行復雜收集操作

Collectors 提供了多種收集器,可以進行復雜的結果收集。例如,收集到 Map:

List<String> words = Arrays.asList("Java", "Stream", "API");
Map<Integer, List<String>> wordLengthMap = words.stream().collect(Collectors.groupingBy(String::length));

4.8 使用 Optional 處理可能的空值

Stream API 中的某些終端操作會返回 Optional,例如 findFirstfindAny。使用 Optional 可以避免空指針異常:

List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> firstWord = words.stream().findFirst();
firstWord.ifPresent(System.out::println);

Java 8 的 Stream API 為集合數據的處理提供了一種高效、簡潔的方式。通過理解和掌握 Stream 的基本概念、常用操作以及最佳實踐,可以大大提高 Java 開發的生產力和代碼質量。

Stream API 不僅支持順序流,還支持并行流,使得在多核環境下處理大量數據變得更加高效。在實際開發中,合理使用 Stream API 可以顯著提升代碼的可讀性和穩定性。

黑馬程序員免費預約咨詢

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/24079.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/24079.shtml
英文地址,請注明出處:http://en.pswp.cn/web/24079.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSRF 令牌的生成過程和檢查過程

在 Django 中,CSRF 令牌的生成和檢查過程是通過 Django 的 CSRF 中間件 (CsrfViewMiddleware) 和模板標簽 ({% csrf_token %}) 自動處理的。以下是詳細的生成和檢查過程: CSRF 令牌的生成過程 用戶訪問頁面: 當用戶第一次訪問頁面時,Django 會為用戶創建一個會話。如果用戶…

人工智能、深度學習和機器學習的前世今生

人工智能、深度學習和機器學習的前世今生 引言 在當今科技飛速發展的時代&#xff0c;人工智能&#xff08;AI&#xff09;、機器學習&#xff08;ML&#xff09;和深度學習&#xff08;DL&#xff09;已經成為引領第四次工業革命的重要力量。這些技術不僅在學術界和工業界掀…

C++ 數據共享與保護學習記錄【代碼】

一.項目一 1.頭文件.h //A.h #pragma once //防止頭文件被重復包含&#xff08;重復包含會被重復編譯&#xff0c;也就是該類會被重復定義&#xff09; #ifndef HEAD_H //等價于&#xff08; #if !defined(HEAD_H) ) //defined是一個預處理操作符&#xff0c;相當于一個表達式…

整理好了!2024年最常見 20 道分布式、微服務面試題(二)

上一篇地址&#xff1a;整理好了&#xff01;2024年最常見 20 道分布式、微服務面試題&#xff08;一&#xff09;-CSDN博客 三、請解釋CAP定理及其含義。 CAP定理是分布式計算領域的一個基本概念&#xff0c;由計算機科學家Eric Brewer在2000年提出&#xff0c;并由科學家Se…

力扣76.最小覆蓋子串

力扣76.最小覆蓋子串 用哈希表記錄每個字母出現次數 枚舉右端點 判斷是否能全覆蓋如果可以 并且更短 就更新 j 縮小區間再判斷 class Solution {bool is_covered(int cnt_s[], int cnt_t[]) {for (int i A; i < Z; i) {if (cnt_s[i] < cnt_t[i]) {return false;}}fo…

上網操作的必要條件

一、 網卡 1、 為什么需要網卡 計算機為了實現網絡通信&#xff0c;必須都要有網卡這個東西&#xff0c;網卡是計算機眾多外部設備之一&#xff08;其它還有硬盤、鍵盤等&#xff09;&#xff0c;計算機將數據發給網卡&#xff0c;網卡負責將數據往外發送&#xff0c;通過IP定…

技術團隊的沖突管理: 谷歌亞里士多德項目的啟示

有效的沖突管理對于技術團隊保持高效和創新的工作環境至關重要。谷歌的亞里士多德項目是一項內部研究&#xff0c;旨在了解成功團隊的因素&#xff0c;強調了心理安全和開放溝通在促進團隊成員之間的合作和解決分歧方面的重要性。本文將探討受谷歌的亞里士多德項目和其他數據點…

工廠生產計劃難以執行的真正原因及對策

在制造業中&#xff0c;生產計劃的執行對于企業的運營至關重要。然而&#xff0c;許多工廠在生產計劃執行過程中面臨著諸多挑戰&#xff0c;尤其是物料齊套率低的問題。本文將探討工廠生產計劃難以執行的真正原因&#xff0c;并提出相應的解決對策。 一、生產計劃難以執行的真…

mysql optimizer_switch : 查詢優化器優化策略深入解析

碼到三十五 &#xff1a; 個人主頁 在 MySQL 數據庫中&#xff0c;查詢優化器是一個至關重要的組件&#xff0c;它負責確定執行 SQL 查詢的最有效方法。為了提供DBA和開發者更多的靈活性和控制權&#xff0c;MySQL 引入了 optimizer_switch 系統變量。這個強大的工具允許用戶開…

nginx配置WebSocket參數wss連接

目錄 一、原文連接 二、 配置參數 三、實踐 四、重啟nginx 五、連接websocket 一、原文連接 nginx配置websocket支持wss-騰訊云開發者社區-騰訊云 二、 配置參數 map $http_upgrade $connection_upgrade { default upgrade; close; } upstream websocket { se…

聚類的外部指標(Purity, ARI, NMI, ACC) 和內部指標(NCC,Entropy,Compactness,Silhouette Index)

在聚類分析中,外部指標和內部指標用于評估聚類結果的質量。外部指標需要知道真實的類別標簽,而內部指標則僅基于聚類結果本身進行評估。 外部指標 Purity (純度): 計算聚類結果中每個簇中最多數目的樣本所屬的類別,并計算所有簇的該類別樣本數之和占所有樣本數的比例。 Pyt…

【操作系統】進程與線程的區別及總結(非常非常重要,面試必考題,其它文章可以不看,但這篇文章最后的總結你必須要看,滿滿的全是干貨......)

目錄 一、 進程1.1 PID(進程標識符)1.2 內存指針1.3 文件描述符表1.4 狀態1.5 優先級1.6 記賬信息1.7 上下文 二、線程三、總結&#xff1a;進程和線程之間的區別&#xff08;非常非常非常重要&#xff0c;面試必考題&#xff09; 一、 進程 簡單來介紹一下什么是進程&#xf…

win 系統 cmd 命令從私庫上傳,下載jar包

1. 確保maven環境變量或者maven安裝無誤&#xff1b; 2.私庫下載 命令 mvn dependency:get -DgroupId<your_group_id> -DartifactId<your_artifact_id> -Dversion<your_version> -Dpackagingjar -Dfile<path_to_your_jar_file> -Durl<your_privat…

寫入文件內容

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在實例01中&#xff0c;雖然創建并打開一個文件&#xff0c;但是該文件中并沒有任何內容&#xff0c;它的大小是0KB。Python的文件對象提供了write()…

【電路筆記】-分貝

分貝 分貝是以 10 為底的對數比,用于表示電路中功率、電壓或電流的增加或減少。 1、概述 一般來說,分貝是響度的度量。 在設計或使用放大器和濾波器電路時,計算中使用的一些數字可能非常大或非常小。 例如,如果我們將兩個放大器級級聯在一起,功率或電壓增益分別為 20 和…

os和os.path模塊

自學python如何成為大佬(目錄):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 目錄也稱文件夾&#xff0c;用于分層保存文件。通過目錄可以分門別類地存放文件。我們也可以通過目錄快速找到想要的文件。在Python中&#xff0c;并…

033.搜索旋轉排序數組

題意 整數數組 nums 按升序排列&#xff0c;數組中的值 互不相同 。 在傳遞給方法之前&#xff0c;nums 在預先未知的某個下標 k(0 < k < nums.length)上進行了旋轉&#xff0c;使數組變為 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]&…

古字畫3d立體在線數字展覽館更高效便捷

在數字時代的浪潮中&#xff0c;大連圖書館以嶄新的面貌躍然屏幕之上——3D全景圖書館。這座承載著城市文化精髓與豐富知識資源的數字圖書館&#xff0c;利用前沿的三維建模技術&#xff0c;為我們呈現了一個全新的知識世界。 隨時隨地&#xff0c;無論您身處何地&#xff0c;只…

獲得抖音商品評論 API 返回值

公共參數 名稱類型必須描述keyString是調用key&#xff08;獲取key和密鑰???????&#xff09;secretString是調用密鑰api_nameString是API接口名稱&#xff08;包括在請求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString否[yes,no]默認yes&am…

信息學奧賽初賽天天練-22-C++基礎關鍵字、進制轉換、結構體與聯合體的實用技巧大揭秘

PDF文檔公眾號回復關鍵字:20240607 單項選擇題&#xff08;共15題&#xff0c;每題2分&#xff0c;共計30分&#xff1a;每題有且僅有一個正確選項&#xff09; 1 在C中&#xff0c;下面哪個關鍵字用于聲明一個變量&#xff0c;其值不能被修改&#xff1f;&#xff08; &#…