Java 8 Stream 流操作全解析

文章目錄

    • **一、Stream 流簡介**
    • **二、Stream 流核心操作**
      • **1. 創建 Stream**
      • **2. 中間操作(Intermediate Operations)**
        • **filter(Predicate<T>):過濾數據**
          • **1. 簡單條件過濾**
          • **2. 多條件組合**
          • **3. 過濾對象集合**
          • **4. 過濾 `null` 值**
        • **2. map(Function<T, R>):轉換元素**
          • **一、`map` 的核心特性**
          • **2. 提取對象屬性**
          • **3. 復雜轉換邏輯**
        • **3. flatMap(Function<T, Stream<R>>):扁平化嵌套結構**
        • **4. distinct():去重**
        • **5. sorted():排序**
        • **6. limit(n) 和 skip(n):分頁控制**
    • **三、高級用法**
        • **1. 分組與分區**
        • **2. 并行流處理**
        • **3. 原始類型流**
        • **四、實際應用場景示例**
          • **1. 數據轉換與過濾**
          • **2. 統計與匯總**
          • **3. 復雜集合處理**
          • **4. 分組統計**
        • **五、注意事項與最佳實踐**
        • **六、與傳統循環的對比**

一、Stream 流簡介

Java 8 引入的 Stream 提供了一種高效、聲明式處理集合數據的方式,支持順序和并行操作,核心特點包括:

  • 鏈式調用:通過組合中間操作(如 filter, map)和終端操作(如 collect, forEach)實現復雜邏輯。
  • 延遲執行:只有終端操作觸發時才會執行中間操作。
  • 不可重用:每個流只能被消費一次。

二、Stream 流核心操作

1. 創建 Stream

  • 集合創建Collection.stream()parallelStream()

    List<String> list = Arrays.asList("a", "b", "c");
    Stream<String> stream = list.stream();
    
  • 數組創建Arrays.stream(array)

    String[] arr = {"a", "b", "c"};
    Stream<String> stream = Arrays.stream(arr);
    
  • 靜態方法Stream.of() 或生成無限流 Stream.iterate(), Stream.generate()

    Stream<Integer> numbers = Stream.of(1, 2, 3);
    Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2); // 0, 2, 4, ...
    

2. 中間操作(Intermediate Operations)

filter(Predicate):過濾數據

作用:根據條件篩選元素,保留滿足條件的元素。
示例

List<String> filtered = list.stream().filter(s -> s.startsWith("a"))  // 保留以"a"開頭的字符串.collect(Collectors.toList());

最佳實踐

1. 簡單條件過濾

篩選出符合條件的元素。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 篩選所有偶數
List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList()); // [2, 4, 6]
2. 多條件組合

使用邏輯運算符 &&(與)、||(或)組合條件。

List<String> words = Arrays.asList("apple", "banana", "cherry", "date");// 篩選長度大于5 且 以字母a開頭的單詞
List<String> result = words.stream().filter(s -> s.length() > 5 && s.startsWith("b")).collect(Collectors.toList()); // ["banana"]
3. 過濾對象集合

根據對象屬性篩選數據。

class User {String name;int age;// 構造方法、getter/setter 省略
}List<User> users = Arrays.asList(new User("Alice", 25),new User("Bob", 17),new User("Charlie", 30)
);// 篩選年齡 >= 18 的用戶
List<User> adults = users.stream().filter(user -> user.getAge() >= 18).collect(Collectors.toList()); // [Alice, Charlie]
4. 過濾 null

使用 Objects::nonNull 過濾掉 null 元素。

List<String> listWithNulls = Arrays.asList("a", null, "b", null, "c");// 過濾掉所有 null 值
List<String> nonNullList = listWithNulls.stream().filter(Objects::nonNull).collect(Collectors.toList()); // ["a", "b", "c"]

2. map(Function<T, R>):轉換元素

map 是 Java Stream 中最核心的中間操作之一,用于將流中的元素一對一轉換為另一種形式。它的本質是通過一個函數(Function<T, R>)對每個元素進行映射,生成新的元素流。以下是 map 的深入解析,涵蓋使用場景、底層機制、最佳實踐與常見問題。


一、map 的核心特性
  1. 一對一轉換:每個輸入元素對應一個輸出元素,元素數量不變。
  2. 類型轉換:輸入類型 T 可轉換為任意輸出類型 R(如 StringInteger)。
  3. 惰性求值:只有終端操作觸發時才會執行映射邏輯。
  4. 無副作用:理想情況下,映射函數不修改外部狀態(符合函數式編程原則)。

作用:將元素轉換為另一種類型或提取特定屬性。

1. 簡單類型轉換

// 將字符串轉換為大寫
List<String> upperCaseList = Arrays.asList("apple", "banana", "cherry").stream().map(String::toUpperCase).collect(Collectors.toList()); // ["APPLE", "BANANA", "CHERRY"]
2. 提取對象屬性
// 從User對象中提取name屬性
List<String> names = users.stream().map(User::getName).collect(Collectors.toList());
3. 復雜轉換邏輯
// 將字符串轉換為自定義DTO對象
List<DataDTO> dtos = strings.stream().map(s -> {DataDTO dto = new DataDTO();dto.setValue(s.length());dto.setLabel(s.toUpperCase());return dto;}).collect(Collectors.toList());

3. flatMap(Function<T, Stream>):扁平化嵌套結構

作用:將嵌套集合(如 List<List<T>>)展開為單一流。
示例

List<List<String>> nestedList = Arrays.asList(Arrays.asList("a", "b"),Arrays.asList("c", "d")
);
List<String> flatList = nestedList.stream().flatMap(Collection::stream)  // 將每個List<String>轉換為Stream<String>.collect(Collectors.toList()); // ["a", "b", "c", "d"]

典型場景

  • 處理數據庫查詢的多表關聯結果。
  • 合并多個API響應的數據列表。

4. distinct():去重

作用:基于 equals()hashCode() 去重。
示例

List<Integer> unique = numbers.stream().distinct().collect(Collectors.toList()); // [1, 2, 3]

關鍵點

  • 自定義對象去重:需重寫 equals()hashCode()

    class User {private Long id;@Overridepublic boolean equals(Object o) { /* 基于id比較 */ }@Overridepublic int hashCode() { /* 基于id生成 */ }
    }
    
  • 性能注意:對大數據集去重可能消耗內存,可結合 limit 分批次處理。


5. sorted():排序

作用:按自然順序或自定義比較器排序。
示例

List<String> sorted = list.stream().sorted(Comparator.reverseOrder())  // 逆序排序.collect(Collectors.toList());

優化建議

  • 盡早過濾:先 filter 減少待排序數據量。
  • 避免頻繁排序:對需要多次排序的場景,考慮轉換為有序集合(如 TreeSet)。

6. limit(n) 和 skip(n):分頁控制

作用skip 跳過前N個元素,limit 限制返回數量。
示例

List<Integer> result = Stream.iterate(0, n -> n + 1).skip(5)   // 跳過0-4,從5開始.limit(10) // 取5-14.collect(Collectors.toList());

應用場景

  • 分頁查詢:模擬數據庫分頁。

    int page = 2, size = 10;
    List<User> users = allUsers.stream().skip((page - 1) * size).limit(size).collect(Collectors.toList());
    
  • 性能注意:對非順序流(如并行流),skiplimit 可能無法保證預期結果。

  • 3. 終端操作(Terminal Operations)

  • 遍歷元素forEach(Consumer<T>)

    list.stream().forEach(System.out::println);
    
  • 收集結果collect(Collector)

    List<String> list = stream.collect(Collectors.toList());
    Set<String> set = stream.collect(Collectors.toSet());
    String joined = stream.collect(Collectors.joining(", "));
    
  • 統計數量count()

    long count = list.stream().filter(s -> s.length() > 3).count();
    
  • 匹配檢查

    • anyMatch(Predicate<T>):至少一個元素匹配。
    • allMatch(Predicate<T>):所有元素匹配。
    • noneMatch(Predicate<T>):沒有元素匹配。
    boolean hasA = list.stream().anyMatch(s -> s.contains("a"));
    
  • 查找元素

    • findFirst():返回第一個元素(Optional<T>)。
    • findAny():適用于并行流,返回任意元素。
    Optional<String> first = list.stream().findFirst();
    
  • 歸約操作reduce(BinaryOperator<T>)

    Optional<Integer> sum = Stream.of(1, 2, 3).reduce(Integer::sum); // 6
    

三、高級用法

1. 分組與分區
  • 分組Collectors.groupingBy()

    Map<Integer, List<String>> groupByLength = list.stream().collect(Collectors.groupingBy(String::length)); // 按字符串長度分組
    
  • 分區Collectors.partitioningBy()

    Map<Boolean, List<String>> partition = list.stream().collect(Collectors.partitioningBy(s -> s.length() > 3)); // 按條件分為兩組
    
2. 并行流處理
  • 創建并行流.parallel()parallelStream()

    List<String> result = list.parallelStream().filter(s -> s.length() > 3).collect(Collectors.toList());
    
  • 注意事項

    • 確保操作線程安全(如避免修改共享變量)。
    • 并行流可能不適用于小數據量或復雜中間操作。
3. 原始類型流
  • 避免裝箱開銷:使用 IntStream, LongStream, DoubleStream

    IntStream.range(1, 5).forEach(System.out::println); // 1, 2, 3, 4
    LongStream.of(10L, 20L).sum();
    

四、實際應用場景示例
1. 數據轉換與過濾
// 從用戶列表中提取成年用戶的姓名
List<String> adultNames = users.stream().filter(user -> user.getAge() >= 18).map(User::getName).collect(Collectors.toList());
2. 統計與匯總
// 計算訂單總金額
double totalAmount = orders.stream().mapToDouble(Order::getAmount).sum();
3. 復雜集合處理
// 將多個訂單的商品列表合并并去重
Set<String> allProducts = orders.stream().flatMap(order -> order.getProducts().stream()).collect(Collectors.toSet());
4. 分組統計
// 按部門分組統計員工平均工資
Map<String, Double> avgSalaryByDept = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.averagingDouble(Employee::getSalary));

五、注意事項與最佳實踐
  1. 避免副作用:在流操作中不要修改外部變量,尤其是在并行流中。
  2. 優先使用無狀態操作:如 filter, mapsorted, distinct 更高效。
  3. 謹慎使用并行流:僅在數據量大且操作耗時的情況下考慮并行化。
  4. 減少裝箱開銷:對數值操作使用原始類型流(IntStream 等)。
  5. 合理使用短路操作:如 findFirst(), limit() 可提前終止流處理。

六、與傳統循環的對比
場景傳統循環Stream 流
簡單遍歷直接易讀代碼更簡潔,但可能略微性能開銷
復雜數據處理需多層嵌套循環,代碼冗長鏈式調用,邏輯清晰
并行處理需手動管理線程和同步通過 .parallel() 自動并行化
函數式編程支持需額外工具類配合原生支持 Lambda 和方法引用

通過掌握 Stream 流的常見用法,可以顯著提升代碼的可讀性和開發效率,尤其在處理集合數據時,能夠以更簡潔的方式實現復雜的數據操作。

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

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

相關文章

Java——設計模式(Design Pattern)

設計模式&#xff08;Design Pattern&#xff09;是軟件開發中針對常見問題的經典解決方案&#xff0c;由 GoF&#xff08;Gang of Four&#xff09;在《設計模式&#xff1a;可復用面向對象軟件的基礎》一書中歸納為23 種模式&#xff0c;分為三大類&#xff1a;創建型模式、結…

python語法學習

1.python的類的定義 class Memory_Manager: 2.__init__ 方法 __init__ 是類的構造方法&#xff0c;用于初始化類的實例。 self 是類實例的引用&#xff0c;用于訪問類的屬性和方法。 3.方法定義 類中的方法是類的功能實現&#xff0c;通過 def 定義。 4.if __name__ __ma…

如何屏蔽mac電腦更新提醒,禁止系統更新(最新有效方法)

每次打開Mac電腦時&#xff0c;頻繁的系統更新提醒可能會對我們的工作和使用體驗造成干擾。為了屏蔽這些更新提醒并禁止系統自動更新&#xff0c;我們可以通過修改Hosts文件來實現。以下是詳細步驟和方法&#xff0c;幫助你徹底屏蔽macOS的更新提醒。 系統關閉了自動更新也是…

windows10重裝ssh無法下載

問題 windows10重裝之后&#xff0c;ssh每次都是由于連接的是流量計數的網絡無法下載。 解決方法 https://www.cnblogs.com/zhg1016/p/17353348.html

解決 cursor 中不能進入 conda 虛擬環境

【問題】 遇到一個小問題&#xff0c;我創建的conda 環境在 cmd、powershell中都可以激活&#xff0c;但在pycharm、cursor中卻不能激活&#xff1f; 看圖 cmd中正常&#xff1a; cursor中不正常&#xff1a; 【解決方法】 cursor 中&#xff0c;打開終端&#xff0c;輸入&a…

跨平臺三維可視化與圖形庫.VTK圖形庫.

1. 科學數據可視化 體繪制&#xff08;Volume Rendering&#xff09; 用于醫學影像&#xff08;如CT、MRI&#xff09;、氣象數據&#xff08;如云層、流體模擬&#xff09;的三維渲染&#xff0c;支持透明度、光照和顏色映射。 等值面提取&#xff08;Iso-Surfacing&#xff…

【螢火工場GD32VW553-IOT開發板】ADC電壓的LabVIEW采集

【螢火工場GD32VW553-IOT開發板】ADC電壓的LabVIEW采集 &#x1f50b; 本文介紹了螢火工場 GD32VW553-IOT 開發板通過串口中斷查詢的方式采集 ADC 電壓及溫度轉換數據&#xff0c;并進一步結合LabVIEW上位機實現數據自動采集和實時監測的項目設計。 項目介紹 串口中斷查詢&a…

視頻監控管理平臺EasyCVR結合AI分析技術構建高空拋物智能監控系統,筑牢社區安全防護網

高空拋物嚴重威脅居民生命安全與公共秩序&#xff0c;傳統監管手段存在追責難、威懾弱等問題。本方案基于EasyCVR視頻監控與AI視頻分析技術&#xff08;智能分析網關&#xff09;&#xff0c;構建高空拋物智能監控系統&#xff0c;實現24小時實時監測、智能識別與精準預警&…

Python----循環神經網絡(LSTM:長短期記憶網絡)

一、RNN的長期依賴問題 可以看到序列越長累乘項項數越多&#xff0c;項數越多就可能會讓累乘結果越小&#xff0c;此時對于W 的更新就取決于第一項或者是前幾項&#xff0c;也就是RNN模型會丟失很多較遠時刻的信息而 更關注當前較近的幾個時刻的信息&#xff0c;即沒有很好的長…

【跨端框架檢測】使用adb logcat檢測Android APP使用的跨端框架方法總結

目錄 Weex 跨端框架使用了uni-app的情況區分使用了uni-app還是Weex 判斷使用了Xamarin判斷使用了KMM框架判斷使用了 ??Ionic 框架判斷使用了Cordova框架判斷使用了Capacitor 框架使用了React Native框架使用了QT框架使用了Cocos框架使用了Electron 框架使用了flutter 框架使用…

以加減法計算器為例,了解C++命名作用域與函數調用

************* C topic: 命名作用域與函數調用 ************* The concept is fully introducted in the last artical. Please refer to 抽象&#xff1a;C命名作用域與函數調用-CSDN博客 And lets make a calculator to review the basic structure in c. 1、全局函數 A…

AIGC小程序項目

一、文生文功能 &#xff08;1&#xff09;前端部分 使用 Pinia 狀態管理庫創建的聊天機器人消息存儲模塊&#xff0c;它實現了文生文&#xff08;文本生成文本&#xff09;的核心邏輯。 1.Pinia狀態管理 這個模塊管理兩個主要狀態&#xff1a; messages&#xff1a;存儲所…

Axios中POST、PUT、PATCH用法區別

在 Axios 中&#xff0c;POST、PUT 和 PATCH 是用于發送 HTTP 請求的三種不同方法&#xff0c;它們的核心區別源自 HTTP 協議的設計語義。以下是它們的用法和區別&#xff1a; 1. POST 語義&#xff1a;用于創建新資源。 特點&#xff1a; 非冪等&#xff08;多次調用可能產生…

[爬蟲知識] Cookie與Session

相關實戰案例&#xff1a;[爬蟲實戰] 爬取小說標題與對應內容 相關爬蟲專欄&#xff1a;JS逆向爬蟲實戰 爬蟲知識點合集 爬蟲實戰案例 一、引入場景 在http協議中&#xff0c;瀏覽器是無狀態&#xff08;即無記憶&#xff09;的&#xff0c;對于請求與響應的產生數據&#…

怎樣改變中斷優先級?

在STM32中改變中斷優先級可以通過STM32CubeMX配置和代碼中設置兩種方式來實現。以下以STM32F1系列為例進行說明: 使用STM32CubeMX配置 打開工程:在STM32CubeMX中打開你的工程。進入NVIC配置:在Pinout & Configuration選項卡中,點擊NVIC進入中斷向量控制器配置界面。選…

科學計算中的深度學習模型精解:CNN、U-Net 和 Diffusion Models

關鍵要點 模型概述:卷積神經網絡(CNN)、U-Net 和 Diffusion Models 是深度學習中的核心模型,廣泛應用于科學計算任務,如偏微分方程(PDE)求解、圖像分割和數據生成。科學計算應用:CNN 可用于高效求解 PDEs,U-Net 擅長醫學圖像分割和材料分析,Diffusion Models 在生成合…

解決Docker無法拉取鏡像問題:Windows系統配置鏡像加速全指南

問題背景 在使用 Docker 時&#xff0c;你是否遇到過以下報錯&#xff1f; Unable to find image ‘mysql:latest’ locally docker: Error response from daemon: Get “https://registry-1.docker.io/v2/”: dial tcp 128.242.250.155:443: i/o timeout. 這類問題通常是由于…

Spring AI 使用教程

Spring AI 使用教程&#xff08;2025年5月24日更新&#xff09; 一、環境搭建與項目初始化 創建Spring Boot項目 使用IDEA或Spring Initializr創建項目&#xff0c;選擇JDK 17或更高版本&#xff08;推薦21&#xff09;。勾選依賴項&#xff1a;Spring Web、Lombok&#xff0c;…

iOS 直播特殊禮物特效實現方案(Swift實現,超詳細!)

特殊禮物特效是提升直播互動體驗的關鍵功能&#xff0c;下面我將詳細介紹如何在iOS應用中實現各種高級禮物特效。 基礎特效類型 1.1 全屏動畫特效 class FullScreenAnimationView: UIView {static func show(with gift: GiftModel, in view: UIView) {let effectView FullS…

分布式事務之Seata

概述 Seata有四種模式 AT模式&#xff1a;無侵入式的分布式事務解決方案&#xff0c;適合不希望對業務進行改造的場景&#xff0c;但由于需要添加全局事務鎖&#xff0c;對影響高并發系統的性能。該模式主要關注多DB訪問的數據一致性&#xff0c;也包括多服務下的多DB數據訪問…