《Java Stream 流從入門到精通:一行代碼搞定集合操作,效率提升 10 倍》

封面圖上流動的「Stream」字樣,正是 Java 8 以來最革命性的特性之一!你是否還在寫冗長的 for 循環遍歷集合?是否為過濾、排序、聚合數據寫一堆重復代碼?Stream 流的出現,以聲明式編程風格將復雜的集合操作濃縮為一行代碼,不僅可讀性更強,還能輕松實現并行處理。本文將從 Stream 的核心概念(中間操作 / 終止操作)講起,結合 10 + 實戰案例(過濾去重、分組統計、鏈式調用),帶你吃透 Stream 流的精髓,讓代碼更優雅、更高效!


Stream API ?萬物皆可一行代碼
Stream專門針對集合的各種操作提供各種非常便利,簡單,高效的API,
Stream API主要是通過Lambda表達式完成,極大的提高了程序的效率和可讀性,
同時Stram API中自帶的并行流使得并發處理集合的門檻再次降低,使用Stream API編程無需多寫

怎樣使用Stream流?

1. 獲取流-->? 2. 對流進行操作-->3.結束對流的操作

獲取流的方式

集合類可通過 Collection.stream()Collection.parallelStream() 獲取流;

數組可通過 Arrays.stream(T[] array)Stream.of() 轉換。

IO 相關流如 Files.walk()BufferedReader.lines() 也可生成流。


中間操作(Intermediate Operations)

中間操作返回新流,支持鏈式調用,操作延遲執行(lazy)。

映射操作

  • map:元素一對一轉換。
    List<String> names = students.stream().map(Student::getName).collect(Collectors.toList());
    
  • flatMap:扁平化多維結構。
    List<String> words = lines.stream().flatMap(line -> Arrays.stream(line.split(" "))).collect(Collectors.toList());
    

過濾與去重

  • filter:保留符合謂詞的元素。
    List<Student> adults = students.stream().filter(s -> s.getAge() > 18).collect(Collectors.toList());
    
  • distinct:去除重復元素(依賴 equals 方法)。

排序與裁剪

  • sorted:自然排序或自定義比較器。

在Java流(Stream) API中,sorted方法用于對流中的元素進行排序操作。它支持兩種重載形式,可以根據需要選擇無參數或傳入自定義比較器(Comparator)。下面我將逐步解釋其用法,并提供真實可靠的示例代碼,幫助您理解如何高效實現排序。

1. 無參數sorted方法
  • 當調用sorted()方法而不傳遞任何參數時,要求流中的元素必須實現Comparable<T>接口。這適用于元素類已經定義了自然排序順序的情況。
  • 示例:如果元素類(如String或自定義類)實現了Comparable,則可以直接使用。
    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    names.stream().sorted()  // 依賴String的Comparable實現.forEach(System.out::println);
    
    輸出結果將是按字母順序排序的元素:Alice, Bob, Charlie
2. 帶Comparator參數的sorted方法
  • 方法簽名:Stream<T> sorted(Comparator<? super T> comparator)

  • 這允許您傳入一個自定義比較器來定義排序規則,特別適用于元素類未實現Comparable或需要特定排序邏輯的場景。

  • 使用lambda表達式可以簡潔地定義比較器。

    • 示例:基于對象的屬性(如年齡)排序。
      List<Student> students = Arrays.asList(new Student("Alice", 20),new Student("Bob", 18),new Student("Charlie", 22)
      );// 使用lambda表達式排序:按年齡從小到大
      students.stream().sorted((s1, s2) -> Integer.compare(s1.getAge(), s2.getAge())).forEach(System.out::println);
      
      輸出:按年齡升序顯示學生信息(如Bob(18), Alice(20), Charlie(22))。
  • 更推薦使用Comparator的工廠方法(如Comparator.comparingInt),以提高代碼可讀性和健壯性。

    • 示例:使用Comparator.comparingInt優化排序。
      students.stream().sorted(Comparator.comparingInt(Student::getAge))  // 等價于lambda,但更簡潔.forEach(System.out::println);
      
      輸出與上述相同,但代碼更易于維護。
3. 注意事項和最佳實踐
  • 性能考慮sorted方法是一個有狀態操作,可能影響流性能。對于大數據集,建議在排序前使用parallelStream()(如果線程安全)。
  • 降序排序:可以通過Comparator.reversed()實現降序。
    students.stream().sorted(Comparator.comparingInt(Student::getAge).reversed()).forEach(System.out::println);
    
    輸出:按年齡降序(如Charlie(22), Alice(20), Bob(18))。
  • 多字段排序:使用Comparator.thenComparing實現復合排序。
    students.stream().sorted(Comparator.comparing(Student::getName).thenComparingInt(Student::getAge)).forEach(System.out::println);
    
    先按名字排序,再按年齡排序。
  • limit/skip:截取前 N 項或跳過前 N 項。

調試輔助

  • peek:遍歷元素但不終結流,常用于調試。
    students.stream().peek(s -> System.out.println("Processing: " + s.getName())).collect(Collectors.toList());
    

終結操作(Terminal Operations)

終結操作觸發流處理并返回結果或副作用。

遍歷與聚合

  • forEach:遍歷元素。
    students.stream().forEach(System.out::println);
    
  • count:統計元素數量。
    long count = students.stream().count();
    
  • min/max:需傳入比較器。
    Optional<Student> oldest = students.stream().max(Comparator.comparingInt(Student::getAge));
    

匹配與查找

  • anyMatch/allMatch/noneMatch:檢查元素是否匹配條件。
    boolean hasAdult = students.stream().anyMatch(s -> s.getAge() > 18);
    
  • findFirst/findAny:返回首個或任意元素(并行流中效率更高)。

歸約與收集

2. 使用 Collectors 簡化操作

Collectors 類提供了許多內置轉換器,如 toList()toSet() 等,可以直接傳入 collect 方法。例如:

3. groupingBy 分組操作

groupingBy 類似于 SQL 中的 GROUP BY,用于按指定條件分組元素。它有多個參數版本:

4. toMap 轉換操作

toMap 用于將流轉換為 Map,需指定鍵和值的映射函數。例如:

// 將學生列表轉換為 Map<年齡, 學生對象>
Map<Integer, Student> map = students.stream().collect(Collectors.toMap(Student::getAge, s -> s));

5. 基本數據類型流的限制

對于基本數據類型流(如 IntStreamLongStreamDoubleStream),沒有 collect 方法。這是因為基本類型涉及裝箱(boxing)和拆箱(unboxing)操作,Java SDK 未將其集成到流收集機制中。替代方案是:

  • reduce:聚合元素。
    Optional<Integer> totalAge = students.stream().map(Student::getAge).reduce(Integer::sum);
    
  • collect:轉換為集合或分組。
  • collect 是 Java Stream API 中的一個終端操作,用于將流中的元素收集到一個容器中(如集合或映射)。下面我將基于您提供的信息,逐步解釋 collect 的使用方法、常見場景和注意事項,確保內容真實可靠(基于 Java 8 及以上版本的規范)。

    1. collect 方法的基本簽名

    collect 方法有兩個主要重載形式:

  • 第一個重載:接受三個參數(supplier、accumulator 和 combiner),用于自定義收集邏輯。
    <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);
    
    • supplier:提供一個新容器(如 ArrayList::new)。
    • accumulator:將元素添加到容器中(如 List::add)。
    • combiner:在并行流中合并多個容器(如 List::addAll)。
  • 第二個重載:接受一個 Collector 對象,簡化常見操作。
    <R, A> R collect(Collector<? super T, A, R> collector);
    
    通常,我們使用 Collectors 工具類中的靜態方法作為參數,因為它是更簡潔的方式。
  • 轉換為列表:將流元素收集到 List 中。
    List<Integer> list = integers.stream().collect(Collectors.toList());
    
    默認使用 ArrayList
  • 轉換為集合:將流元素收集到 Set 中。
    Set<Integer> set = integers.stream().collect(Collectors.toSet());
    
    默認使用 HashSet
  • 單參數版本:按分類函數分組,返回 Map
    // 按學生年齡分組,返回 Map<Integer, List<Student>>
    Map<Integer, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getAge));
    
    默認使用 HashMap 作為容器。
  • 多參數版本:支持自定義容器和下游收集器。
    • 兩個參數:指定分類函數和下游收集器(如 toList())。
    • 三個參數:添加容器類型(如 TreeMap::new)。 例如,您提到的例子:按年齡分組,但只收集學生姓名而非整個對象。
    // 按年齡分組,每組存儲學生姓名列表
    Map<Integer, List<String>> map = students.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.mapping(Student::getName, Collectors.toList())));
    
    這里:
    • 第一個參數 Student::getAge 是分類依據。
    • 第二個參數 Collectors.mapping(...) 是下游收集器,其中 mapping 將每個學生映射到姓名,再用 toList() 收集為列表。 如果省略容器參數,默認仍為 HashMap
  • 第一個參數 Student::getAge 定義鍵(key)。
  • 第二個參數 s -> s 定義值(value),這里直接使用學生對象。 注意事項
  • 如果鍵重復,會拋出 IllegalStateException。解決方法是添加第三個參數(合并函數),如 (oldValue, newValue) -> oldValue 保留第一個值。
  • 默認使用 HashMap,但可以通過第四個參數指定其他 Map 實現(如 TreeMap::new)。
  • 使用 toArray() 方法轉換為數組。
    int[] array = intStream.toArray();
    
  • 或者,先將流轉換為對象流(如 boxed()),再使用 collect
    List<Integer> list = intStream.boxed().collect(Collectors.toList());
    
  • 特殊轉換
  • toArray:轉為數組,可指定類型。
    Student[] array = students.stream().toArray(Student[]::new);
    

并行流注意事項

通過 parallelStream() 可啟用并行處理,但需確保操作無狀態且避免共享變量。以下場景適合并行流:

  • 數據量較大且處理耗時。
  • 任務可獨立分片(如過濾、映射)。
List<Student> adults = students.parallelStream().filter(s -> s.getAge() > 18).collect(Collectors.toList());

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

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

相關文章

前端筆記2025

前端 與后端交互 下載后端接口的文件時&#xff0c;若是二進制&#xff0c;需要在請求中添加responseType: ‘blob’ 例如 axios.get(‘http://127.0.0.1:8612/api/daily/report/tdjzxz?selectedMonth2022-06’, { headers: { ‘Accesstoken’: ‘f033b94655f84386a0c112b41…

【LeetCode每日一題】226. 翻轉二叉樹 101. 對稱二叉樹

每日一題226. 翻轉二叉樹題目總體思路代碼101. 對稱二叉樹題目總體思路代碼知識點2025.9.5226. 翻轉二叉樹 題目 給你一棵二叉樹的根節點 root &#xff0c;翻轉這棵二叉樹&#xff0c;并返回其根節點。 示例 1&#xff1a; 輸入&#xff1a;root [4,2,7,1,3,6,9] 輸出&am…

【RNN-LSTM-GRU】第三篇 LSTM門控機制詳解:告別梯度消失,讓神經網絡擁有長期記憶

深入剖析LSTM的三大門控機制&#xff1a;遺忘門、輸入門、輸出門&#xff0c;通過直觀比喻、數學原理和代碼實現&#xff0c;徹底理解如何解決長期依賴問題。1. 引言&#xff1a;為什么需要LSTM&#xff1f;在上一篇講解RNN的文章中&#xff0c;我們了解到??循環神經網絡&…

殘差去噪擴散模型

論文題目:Residual Denoising Diffusion Models(殘差去噪擴散模型) 會議:CVPR2024 摘要:殘差去噪擴散模型(RDDM)是一種新的雙重擴散過程,它將傳統的單一去噪擴散過程解耦為殘差擴散和噪聲擴散。這種雙重擴散框架通過引入殘差,將基于去噪的擴散模型擴展為一種統一的、可…

MySQL與ES索引區別

MySQL與ES索引區別 MySQL索引像字典目錄&#xff0c;ES索引更像整個圖書館的書籍分類系統。 關鍵限制&#xff1a;MySQL單表索引大小影響寫性能&#xff0c;ES的分片數創建后不能改。 比如MySQL的“行”對應ES的“文檔”&#xff0c;MySQL的“表”類似ES的“索引”概念。 MySQL…

vue3圖標終極方案【npm包推薦】vue3-icon-sui(含源碼詳解)

簡介 為徹底實現 vue3 項目圖標自由&#xff0c;特開發此 npm包 vue3-icon-sui&#xff0c;全品類圖標&#xff0c;通通支持&#xff01; iconify 圖標svg 圖標font-class 圖標 安裝 npm i vue3-icon-sui -S使用 按需導入 任意頁面中 import myIcon from "vue3-icon-su…

redis----持久化

Redis 提供了兩種主要的持久化機制&#xff0c;用于將內存中的數據保存到磁盤&#xff0c;以防止服務器重啟或故障導致數據丟失。這兩種機制分別是 RDB&#xff08;Redis Database&#xff09;和 AOF&#xff08;Append Only File&#xff09;。1. RDB 持久化RDB 是 Redis 默認…

Docker快速部署Mongodb主副本集實踐

系列文章目錄 第一章 Mongodb的主副本集 文章目錄系列文章目錄前言一、Mongodb基礎介紹數據庫&#xff08;Database&#xff09;集合&#xff08;Collection&#xff09;文檔&#xff08;Document&#xff09;BSON&#xff08;Binary JSON&#xff09;_id&#xff08;主鍵&…

FC平臺安裝Windows Server2016并連接V6存儲

創建 windows server2016 上傳ISO創建虛擬機安裝OS 加載光盤掛載成功之后&#xff0c;重啟虛擬機重啟之后VNC登錄即可。在FC上安裝windows&#xff0c;安裝完成后&#xff0c;必須安裝tools工具&#xff0c;不然沒有虛擬網卡&#xff0c;無法配置ip地址。Windows主機安裝toolsW…

農業XR數字融合工作站,賦能農業專業實踐學習

隨著數字技術與農業的深度融合&#xff0c;農業專業XR數字融合工作站為農業專業學生提供了沉浸式、交互式的學習體驗。農業專業XR數字融合工作站作為集PC、VR、MR技術于一體的軟硬件集成平臺&#xff0c;通過虛擬仿真、數字孿生等技術手段&#xff0c;有效解決了傳統農業教育中…

積分球的使用——簡易版

這篇寫的比較雜。積分球的功能積分球——測量燈具等光源的總光通量、光效、色溫、顯色指數等參數。使用方法1.開啟積分球系統&#xff08;探測器、光度計、光譜儀&#xff09;&#xff0c;充分預熱&#xff08;15-30分鐘&#xff09;&#xff0c;使得電子設備穩定&#xff0c;減…

[光學原理與應用-435]:晶體光學 - 晶體的結構-基元/原胞/晶胞/點陣

晶體的結構可通過基元、原胞、晶胞和點陣四個核心概念進行系統描述&#xff0c;它們共同揭示了晶體中原子排列的周期性與對稱性規律&#xff0c;具體如下&#xff1a;1. 基元&#xff08;Structure Motif&#xff09;定義&#xff1a;基元是晶體中重復排列的最小結構單元&#…

電腦音頻錄制 | 系統麥克混錄 / 系統聲卡直錄 | 方法匯總 / 常見問題

注&#xff1a;本文為 “電腦音頻錄制 ” 相關合輯。 英文引文&#xff0c;機翻未校。 未整理去重&#xff0c;如有內容異常&#xff0c;請看原文。 How to Record Computer Audio in 6 Free Ways 如何用 6 種免費方式錄制電腦音頻 Sponsored by EaseUS Nov 28, 2023 4:34 a…

2025高教社國賽數學建模競賽B題完整參考論文(含模型和代碼)

2025國賽數學建模競賽B題完整參考論文 目錄 一、 問題重述 1.1 問題背景 1.2 問題回顧與分析 二、 模型假設 三、 符號說明 四、 問題求解與分析 4.1數據預處理 4.2 問題1求解與分析 4.2.1 問題1分析 4.2.2 問題1建模與求解 4.2.3 問題1結果與分析 4.3 問題2求解與分…

OpenSSL 1.0.1e 下載解壓和運行方法(小白適用 附安裝包)?

openssl-1.0.1e.zip? 是 OpenSSL 加密工具包的一個舊版本&#xff08;發布于 2013 年左右&#xff09;的 ?源代碼壓縮包&#xff0c;文件格式是 ZIP 壓縮格式。 一、下載與解壓 ?下載文件? 假如你已經有了 openssl-1.0.1e.zip 這個壓縮包&#xff0c;就跳過這步。 如果沒有…

MapStruct詳解

提到屬性拷貝&#xff0c;首先想到的BeanUtils。 先簡單的回憶下BeanUtils&#xff0c;處理Java Bean之間的屬性拷貝&#xff1b;不過由于它是通過反射來拷貝屬性&#xff0c;在數據量大一些的時候性能會降低&#xff1b; 且在安全方面也會比較弱&#xff1b; MapStruct是編譯期…

8.FC平臺模塊梳理

文章目錄8.FC平臺模塊梳理8.1. 內存復用技術特點應用價值8.2. 虛擬機啟用策略8.3. NUMA8.4. HA高可用8.5. 故障和響應策略8.6. DRS 和 DPM8.7. IMC8.FC平臺模塊梳理 8.1. 內存復用 內存共享內存交換內存氣泡 內存共享&#xff1a;多臺虛擬機共享數據內容相同的內存頁。內存交換…

貪心算法應用:DNA自組裝問題詳解

JAVA中的貪心算法應用&#xff1a;DNA自組裝問題詳解 1. DNA自組裝問題概述 DNA自組裝(DNA Self-Assembly)是分子計算和納米技術中的一個重要問題&#xff0c;它利用DNA分子的互補配對特性&#xff0c;通過精心設計DNA序列&#xff0c;使其自發地組裝成預定的納米結構。在計算機…

數據湖如何打造統一存儲與處理方案(結構化數據、半結構化數據和非結構化數據)

目錄 1. 數據湖的“包容哲學”:為什么需要統一方案? 數據湖的核心訴求 案例:零售企業的痛點 2. 存儲層設計:給數據找個舒適的家 分區與分層存儲 選擇存儲格式 案例:Parquet的威力 云存儲的選擇 3. 元數據管理:給數據湖裝上“導航儀” 元數據管理的核心組件 主流…

AUTOSAR進階圖解==>AUTOSAR_SWS_TTCANDriver

TTCAN驅動器詳細規范 AUTOSAR TTCAN Driver Specification with Enhanced Visual Documentation目錄 1. 概述2. TTCAN控制器狀態機3. TTCAN模塊架構4. TTCAN時間觸發操作序列5. TTCAN錯誤處理流程6. 總結 1. 概述 TTCAN&#xff08;Time-Triggered CAN&#xff09;驅動器是AU…