Java Stream流介紹及使用指南

背景

在Java 8之前,處理集合數據(如List,?Set,?Map)通常意味著編寫冗長的、以操作為中心的代碼:創建迭代器、使用forwhile循環遍歷元素、在循環體內進行條件判斷和操作、收集結果。這種方式雖然有效,但不夠簡潔、可讀性較差,且難以充分利用多核處理器的優勢。

Java 8 引入的 Stream API (java.util.stream) 徹底改變了這一局面。?它提供了一種高效、聲明式、函數式處理數據序列(尤其是集合)的強大抽象。Stream 不是數據結構,而是對數據源(如集合、數組、I/O資源)進行復雜計算操作的流水線。它允許你以聲明式的方式(描述“做什么”,而不是“怎么做”)來表達數據處理邏輯,極大地提升了代碼的簡潔性、可讀性和潛在的性能(尤其是并行處理)。

一、什么是 Stream?

  1. 非數據結構:?Stream 本身不存儲數據。它從數據源(如集合、數組)獲取數據,并攜帶數據流經一系列計算操作。

  2. 函數式操作:?Stream 的操作(如filter,?map,?reduce) 通常接受函數式接口(如Predicate,?Function,?Consumer) 作為參數,這使其天然支持Lambda表達式和方法引用。

  3. 流水線:?Stream 操作被鏈接起來形成一個流水線(Pipeline)。一個Stream操作的結果作為下一個操作的輸入。

  4. 惰性求值:?中間操作(Intermediate Operations)?是惰性的。它們只是聲明了要執行的操作,但不會立即執行。只有終止操作(Terminal Operation)?被調用時,整個流水線才會被觸發執行。

  5. 只能遍歷一次:?一個Stream實例一旦被終止操作消費,就不能再被使用。你需要從原始數據源重新創建一個新的Stream來執行其他操作。

  6. 支持并行:?創建并行Stream(parallelStream())非常簡單,Stream API內部會自動處理線程和分區的復雜性(盡管使用時仍需注意線程安全)。

二、Stream 操作類型

Stream操作主要分為兩類:

  1. 中間操作:

    • filter(Predicate<T> predicate): 過濾元素,保留滿足條件的元素。

    • map(Function<T, R> mapper): 將元素轉換成另一種形式(類型可以改變)。例如,從Student對象中提取name屬性形成新的字符串流。

    • flatMap(Function<T, Stream<R>> mapper): 將每個元素轉換成一個Stream,然后把所有生成的Stream“扁平化”連接成一個Stream。常用于處理嵌套集合(如List<List<String>>)。

    • distinct(): 去除重復元素(依據equals())。

    • sorted()?/?sorted(Comparator<T> comparator): 排序。

    • peek(Consumer<T> action): 對每個元素執行一個操作(通常用于調試,如打印),不影響元素本身。注意:?在并行流中慎用,執行順序不確定。

    • limit(long maxSize): 截取前N個元素。

    • skip(long n): 跳過前N個元素。

    • 總是返回一個新的Stream,允許操作鏈式調用。

    • 惰性執行:?它們只是將操作記錄到流水線上,直到終止操作被調用才真正執行。

  2. 終止操作:

    • forEach(Consumer<T> action): 對每個元素執行操作。

    • toArray(): 將元素收集到數組中。

    • 收集器 (Collectors):?最強大和靈活的終止操作之一。

    • reduce(...): 將元素反復結合,得到一個匯總值(如求和、求最大值)。有多個重載形式(帶初始值、不帶初始值、BinaryOperator)。

    • min(Comparator<T> comparator)?/?max(Comparator<T> comparator): 返回最小/最大元素(基于比較器)。

    • count(): 返回元素數量。

    • anyMatch(Predicate<T> predicate)?/?allMatch(Predicate<T> predicate)?/?noneMatch(Predicate<T> predicate): 檢查是否存在任意/所有/沒有元素匹配給定條件。這些是短路操作(找到結果即停止)。

    • findFirst()?/?findAny(): 返回第一個/任意一個元素(Optional<T>)。findAny()在并行流中效率更高。也是短路操作

    • collect(Collector<T, A, R> collector): 使用Collectors工具類提供的方法(如toList(),?toSet(),?toMap(),?joining(),?groupingBy(),?partitioningBy(),?summingInt(),?averagingDouble()等)將元素匯總成各種形式的結果(集合、字符串、數值統計等)。觸發流水線的執行。

    • 消費Stream并產生一個結果(如一個值、一個集合、void)或副作用。執行后,Stream就被認為已消費,不能再使用。

三、為什么使用 Stream?核心優勢

  1. 聲明式編程:?代碼更清晰、更接近問題描述。你關注的是“過濾出大于10的數”、“提取名稱字段”、“按年齡分組”這樣的邏輯,而不是循環索引和臨時變量。

  2. 簡潔性:?顯著減少樣板代碼(如循環、迭代器、臨時集合)。

  3. 可讀性:?鏈式調用和Lambda表達式使數據處理邏輯一目了然。

  4. 易于并行化:?只需將stream()替換為parallelStream()(或在現有流上調用parallel()),即可嘗試利用多核處理器加速計算。Stream API 內部處理了復雜的線程、同步和數據分區問題。(注意:并行不一定總是更快,需要評估數據量和操作復雜度)

  5. 函數式風格:?鼓勵使用無副作用的純函數,有利于編寫更健壯、可測試的代碼。

  6. 組合性:?中間操作可以靈活組合,構建復雜的數據處理流水線

四、代碼列子

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class StreamDemo {public static void main(String[] args) {List<String> names = Arrays.asList("abc", "java", "python", "David", "Anna", "Edward");// 示例1:過濾以"A"開頭的名字,轉換成大寫,收集到ListList<String> aNamesUpper = names.stream() // 1. 創建流.filter(name -> name.startsWith("A")) // 2. 中間操作:過濾.map(String::toUpperCase) // 3. 中間操作:轉換 (方法引用).collect(Collectors.toList()); // 4. 終止操作:收集// 示例2:計算所有名字長度的總和 (使用mapToInt避免自動拆箱裝箱)int totalLength = names.stream().mapToInt(String::length) // 轉換成IntStream (原始類型流).sum(); // IntStream的終止操作:求和System.out.println("Total Length: " + totalLength);// 示例3:按名字長度分組Map<Integer, List<String>> namesByLength = names.stream().collect(Collectors.groupingBy(String::length));System.out.println(namesByLength);// 示例4:并行流 - 查找任意一個長度大于5的名字 (順序無關緊要時)names.parallelStream().filter(name -> name.length() > 5).findAny().ifPresent(System.out::println); }
}

五、關鍵注意事項

  1. 一次消費:?Stream 只能被終止操作消費一次。之后再次使用會拋出IllegalStateException。需要從原始數據源重新創建。

  2. 避免有狀態的Lambda:?在中間操作的Lambda表達式(特別是并行流中)應避免修改外部狀態(如外部變量),否則可能導致線程安全問題或不可預測的結果。盡量使用無狀態操作和純函數。

  3. 并行流謹慎使用:

    • 開銷:?并行化本身(線程創建、任務調度、結果合并)有開銷。數據量小或操作簡單時,串行流可能更快。

    • 線程安全:?確保數據源、共享狀態、傳遞給操作的Lambda都是線程安全的。避免修改源集合(使用并發集合或確保只讀)。

    • 順序依賴性:?如果操作結果依賴于元素順序(如findFirst(),?limit(),?sorted()在并行流中可能更慢),或者操作本身有狀態(如skip()),并行可能無益甚至有害。

    • 副作用:?在forEachpeek中進行有副作用的操作(如修改共享集合)在并行流中極易出錯。優先使用無副作用的collect進行匯總。

  4. peek用于調試:?peek主要用于調試觀察流水線中間狀態,不應依賴它執行關鍵業務邏輯,尤其在并行流中其執行順序不確定。

  5. 原始類型流:?為避免頻繁的自動裝箱(int?->?Integer)帶來的性能損耗,提供了IntStream,?LongStream,?DoubleStream。使用mapToInt,?mapToLong,?mapToDouble等方法轉換,并使用其專用的方法(如sum(),?average(),?range())。

六、總結

Java Stream API 是現代Java編程中處理集合數據的基礎。它通過聲明式、函數式的風格,顯著提升了代碼的簡潔性、可讀性和潛在性能。理解其核心概念(流水線、惰性求值、中間/終止操作)、熟練掌握常用操作(filter,?map,?collect,?reduce等)以及Collectors工具類的強大功能,是高效利用Stream的關鍵。

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

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

相關文章

JDK 1.7 vs JDK 1.8

JDK版本比較 Java平臺的兩次重大飛躍&#xff1a;JDK 7的穩定優化與JDK 8的革命性創新引言&#xff1a;Java的進化之路Java作為企業級開發的支柱語言&#xff0c;其版本更新直接影響著全球數百萬開發者。JDK 1.7&#xff08;2011年發布&#xff09;和JDK 1.8&#xff08;2014年…

張量與維度

3x4x5的張量&#xff1a; x torch.tensor([[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]], [[21, 22, 23, 24, 25], …

智慧菜場系統(源碼+文檔+講解+演示)

引言 在數字化浪潮的推動下&#xff0c;傳統菜市場也在尋求創新與變革。智慧菜場系統作為一種新型的菜市場管理工具&#xff0c;通過數字化手段優化菜市場的全流程&#xff0c;提高運營效率&#xff0c;增強消費者體驗&#xff0c;提升市場管理質量。本文將詳細介紹智慧菜場系統…

【GESP】C++一級真題 luogu-B4355 [GESP202506 一級] 值日

GESP C一級&#xff0c;2025年6月真題&#xff0c;基礎運算和循環語句&#xff0c;難度★☆☆☆☆。 題目題解詳見&#xff1a;【GESP】C一級真題 luogu-B4355 [GESP202506 一級] 值日 | OneCoder 【GESP】C一級真題 luogu-B4355 [GESP202506 一級] 值日 | OneCoderGESP C一級…

【Linux應用】Ubuntu20.04 aarch64開發板一鍵安裝ROS2(清華源)

【Linux應用】Ubuntu20.04 aarch64開發板一鍵安裝ROS2&#xff08;清華源&#xff09; 文章目錄相關資料更改UTF8執行更新一鍵安裝ROS2驗證配置環境變量附錄&#xff1a;開發板快速上手&#xff1a;鏡像燒錄、串口shell、外設掛載、WiFi配置、SSH連接、文件交互&#xff08;RAD…

【HDLBits習題 2】Circuit - Sequential Logic(4)More Circuits

1. Rule90&#xff08;Rule 90&#xff09;方法1&#xff1a;module top_module (output reg [511:0] q,input clk,input load,input [511:0] data ); integer i;always (posedge clk) beginif (load 1b1) beginq < data;end else beginfor (i0; i<$bits(q);…

基于mysqlfrm工具解析mysql數據結構文件frm表結構和數據庫版本信息

這里使用Linux系統上操作。win上搞了下 python報錯。所以在這里記錄一下推薦大家使用linux系統操作。 安裝mysql utilswget https://downloads.mysql.com/archives/get/p/30/file/mysql-utilities-1.6.5.tar.gztar -xf mysql-utilities-1.6.5.tar.gzcd mysql-utilities-1.6.5py…

【C++ 深入解析 C++ 模板中的「依賴類型」】

深入解析 C 模板中的「依賴類型」 依賴類型是 C 模板編程中的核心概念&#xff0c;特指那些依賴于模板參數的類型。迭代器是依賴類型的常見例子&#xff0c;但遠不止于此。讓我們全面解析這個重要概念&#xff1a; 依賴類型的本質定義 依賴類型是&#xff1a; 在模板中定義直接…

Telnet遠程連接實驗(Cisco)

Telnet遠程連接實驗&#xff08;Cisco&#xff09; 拓撲圖一并實現DHCP服務、HTTP服務、FTP服務。 二層交換機配置&#xff1a; 交換機Switch0配置&#xff1a; vlan 10vlan 20int f0/1switchport mode accessswitchport access vlan 10int f0/2switchport mode accessswitchpo…

C++:非類型模板參數,模板特化以及模板的分離編譯

目錄 一、前言 二、非類型模板參數 三、模板的特化 3.1 類模板特化 3.11 全特化 3.12 偏特化 3.2 函數模板特化 3.3 注意 四、模板的分離編譯 一、前言 前面的文章梳理了模板初階的一些用法&#xff0c;在后面梳理了STL的一些容器的用法后&#xff0c;下面將用到含有S…

【Qt 學習之路】Qt Android開發環境搭建:Ubuntu的Vmware虛擬機中的踩坑實錄

文章目錄1、簡介2、虛擬機內USB設備識別難題2.1、正確連接手機2.2、打開USB相關配置2.3、打開虛擬機中的手機設備3、Gradle下載速度緩慢之困3.1、下載 Gradle 鏡像3.2、安放鏡像位置3.3、修改項目中的gradle路徑1、簡介 許久未曾使用Qt進行Android開發&#xff0c;今日在Ubunt…

MySQL中使用group_concat遇到的問題及解決

在使用group_concat的過程中遇到個問題&#xff0c;這里記錄一下&#xff1a;在MySQL中有個配置參數group_concat_max_len&#xff0c;它會限制使用group_concat返回的最大字符串長度&#xff0c;默認是1024。 查詢group_concat_max_len大小&#xff1a; show variables like…

高性能小型爬蟲語言與代碼示例

高性能小型爬蟲現在有哪幾種新興語言可以選擇。我看到了很多關于爬蟲框架的信息&#xff0c;特別是使用Go語言和Node.js的框架。Go語言方面有Kaola1和Katana2這兩個框架。Kaola被描述為高性能的Go語言爬蟲框架&#xff0c;輕量級且強大&#xff0c;提供靈活配置選項。 Node.js…

【PTA數據結構 | C語言版】在順序表 list 中查找元素 x

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 請編寫程序&#xff0c;將 n 個整數存入順序表&#xff0c;對任一給定整數 x&#xff0c;查找其在順序表中的位置。 輸入格式&#xff1a; 輸入首先在第一行給出正整數 n&#xff08;≤10^4 &#…

claude code-- 基于Claude 4 模型的智能編程工具,重塑你的編程體驗

文章目錄0.前言1.安裝nodejs2.使用指南3.快速上手4.總結0.前言 最近的這個claudecode非常的火&#xff0c;因為可能是這個cursoe定價的一些原因吧&#xff0c;我是聽其他的這個大佬說的&#xff0c;因為這個cursor其實我就是最開始的使用用過一下&#xff0c;現在基本上不使用…

HTTP API 身份認證

互聯網系統通常需要根據用戶身份決定是否有資源的訪問權限&#xff0c;這就需要對用戶進行身份認證&#xff08;Authentication&#xff09;&#xff0c;驗證用戶所聲稱的身份。驗證手段通常是驗證只有用戶知道或擁有的東西&#xff0c;比如密碼、手機號、指紋等。 基于瀏覽器…

Python畢業設計232—基于python+Django+vue的圖書管理系統(源代碼+數據庫)

畢設所有選題&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于pythonDjangovue的圖書管理系統(源代碼數據庫)232 一、系統介紹 本項目前后端分離&#xff0c;分為用戶、管理員兩種角色 1、用戶&#xff1a; 注冊、登錄、新聞資訊、圖書信…

Koa+Puppeteer爬蟲教程頁面設計

當我使用Koa作為web服務器&#xff0c;Puppeteer作為爬蟲工具來編寫一個簡單的爬蟲教程時&#xff0c;發生了戲劇性的一幕。 下面我將創建一個完整的Koa Puppeteer爬蟲教程頁面&#xff0c;包含代碼示例、執行演示和詳細說明。設計思路 左側為教程內容區域右側為實時爬蟲演示區…

云成本優化完整指南:從理論到實踐的全方位解決方案

目錄 引言:云成本管理的重要性云成本優化的核心原則成本分析與監控體系立即行動的快速優化策略中期架構優化方案長期成本治理體系多云環境成本管理實施路線圖與最佳實踐案例研究與效果評估總結與展望引言:云成本管理的重要性 {#引言} 在數字化轉型的浪潮中,

計算機學科專業基礎綜合(408)四門核心課程的知識點總結

一、數據結構&#xff08;Data Structure&#xff09; 數據結構是 “如何高效組織和處理數據” 的學科&#xff0c;核心是邏輯結構&#xff08;數據間的關系&#xff09;和物理結構&#xff08;數據在內存中的存儲方式&#xff09;&#xff0c;以及基于這兩種結構的操作算法。 …