Stream API 新玩法:從 teeing()到 mapMulti()

1. 背景:Stream API 的演進

Java 8 引入 Stream API 以來,Java 的集合處理方式發生了質變。開發者可以用聲明式風格實現復雜的數據轉換與聚合。然而,隨著應用場景多樣化,社區逐漸發現一些“尷尬空缺”:

  • 聚合時,往往需要計算兩個指標(比如總數與平均值),卻只能先 .collect() 一次,再寫邏輯合并,代碼冗余。
  • 一對多映射場景(比如把一條日志展開成多條事件),過去只能用 flatMap(),但其表達力稍顯笨重。

Java 12 開始,JDK 對 Stream 的功能進行了增強,加入了更靈活的收集器和映射器。其中最值得關注的就是 teeing()mapMulti()


2. teeing() 收集器 —— 一次遍歷,雙份結果

2.1 用途

teeing()Java 12 引入的新收集器。它允許我們在一次流處理過程中,同時執行兩個獨立的收集操作,并在結束時用一個合并函數把結果“合并”起來。

2.2 傳統寫法(累贅)

假設我們要計算一組訂單的 總金額平均金額

List<Integer> orders = List.of(100, 200, 300, 400);// 傳統寫法:需要遍歷兩次
int sum = orders.stream().mapToInt(i -> i).sum();
double avg = orders.stream().mapToInt(i -> i).average().orElse(0);

這里 orders.stream() 被遍歷了兩次,在大數據場景下顯得低效。


2.3 teeing() 寫法(優雅)

import static java.util.stream.Collectors.*;var result = orders.stream().collect(teeing(summingInt(Integer::intValue),      // 收集器1:求和averagingInt(Integer::intValue),    // 收集器2:平均(sum, avg) -> String.format("Sum=%d, Avg=%.2f", sum, avg)));System.out.println(result); 
// 輸出: Sum=1000, Avg=250.00

一次遍歷,得到兩個收集結果,再由合并函數包裝成最終對象。


2.4 適用場景

  • 統計類場景(如最大值 & 最小值、總數 & 平均值)
  • 報表生成(一次聚合,多維指標輸出)
  • 性能敏感場景(避免多次遍歷)

3. mapMulti() —— 更強大的 “一對多” 映射

3.1 背景

在 Java 8 的 Stream 中,如果要把一條記錄映射成多條,需要 flatMap()

Stream.of("a:b:c", "d:e").flatMap(s -> Arrays.stream(s.split(":"))).forEach(System.out::println);

flatMap() 可以解決問題,但表達能力有限

  • 必須返回一個流 Stream<T>,有時僅僅想用條件判斷推送幾個元素,卻要額外包裝。
  • 需要注意額外的對象創建(比如數組或中間 Stream)。

3.2 mapMulti() 簡化表達

mapMulti()Java 16 引入,它的思路是:你負責“往下游收集器里塞元素”,JDK 不強制你非得返回一個 Stream。

Stream.of("a:b:c", "d:e").mapMulti((str, downstream) -> {for (String part : str.split(":")) {downstream.accept(part);}}).forEach(System.out::println);

效果等價于上面 flatMap() 示例,但避免了額外的 Arrays.stream()


3.3 高級用法 —— 條件展開

比如:只展開長度大于 1 的子串。

Stream.of("x:yz:abc", "m:n").mapMulti((str, downstream) -> {for (String part : str.split(":")) {if (part.length() > 1) {downstream.accept(part);}}}).forEach(System.out::println);
// 輸出: yz, abc

這種寫法,邏輯更直觀,避免創建一堆中間集合/流。


3.4 適用場景

  • 日志/文本解析:一行可能映射成多條事件。
  • 過濾展開:部分元素不展開,部分元素展開多份。
  • 高性能場景:避免額外 Stream 對象的開銷。

4. 對比小結

特性teeing()mapMulti()
引入版本Java 12Java 16
作用一次遍歷,雙收集結果高效一對多映射
替代兩次 .collect() 或手寫聚合邏輯flatMap()(但更直觀、更高效)
典型應用統計報表、聚合指標日志解析、條件展開

5. flatMap() vs mapMulti() 性能對比

我們寫一段小測試,生成一百萬條帶分隔符的字符串,用 flatMap()mapMulti() 分別展開,觀察耗時。

import java.util.*;
import java.util.stream.*;
import java.time.*;public class MapMultiVsFlatMap {public static void main(String[] args) {// 構造一百萬條字符串List<String> data = IntStream.range(0, 1_000_000).mapToObj(i -> "a:b:c:d:e").toList();// 測試 flatMaplong t1 = System.currentTimeMillis();long count1 = data.stream().flatMap(s -> Arrays.stream(s.split(":"))).count();long t2 = System.currentTimeMillis();// 測試 mapMultilong t3 = System.currentTimeMillis();long count2 = data.stream().mapMulti((s, downstream) -> {for (String part : s.split(":")) {downstream.accept(part);}}).count();long t4 = System.currentTimeMillis();System.out.printf("flatMap count=%d, time=%dms%n", count1, (t2 - t1));System.out.printf("mapMulti count=%d, time=%dms%n", count2, (t4 - t3));}
}

預期結果(不同機器可能略有差異):

flatMap count=5000000, time=242ms
mapMulti count=5000000, time=181ms

可以看到,在數據量大時,mapMulti() 由于避免了中間 Stream 對象的構建,通常會比 flatMap() 更快一些,且內存占用也更低。


6. 總結

Stream API 在 Java 12 之后不斷進化:

  • teeing() 讓我們可以一次性得到多個收集結果,既優雅又高效;
  • mapMulti() 則讓“一對多”的映射邏輯更加自然簡潔

隨著這些增強,Java 的函數式編程能力逐漸補齊了短板,在復雜數據處理場景中變得更加順手。

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

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

相關文章

STM32G4 SVPWM VF開環強拖電機

目錄一、STM32G4 SVPWM VF開環強拖電機1 SVPWM1.1 SVPWM技術簡介1.2 基于零序分量注入的SVPWM算法的實現2. VF開環強拖電機3. VF啟動電機實驗現象附學習參考網址歡迎大家有問題評論交流 (* ^ ω ^)一、STM32G4 SVPWM VF開環強拖電機 1 SVPWM 1.1 SVPWM技術簡介 SVPWM控制策略…

產品運營必備職場通用能力及提升攻略,一文說明白

在互聯網行業蓬勃發展的當下&#xff0c;產品運營崗位成為了連接產品、用戶與商業目標的關鍵紐帶。從用戶增長到活動策劃&#xff0c;從數據分析到跨部門協作&#xff0c;產品運營人員需具備多元化技能&#xff0c;才能在激烈競爭中嶄露頭角。隨著企業對精細化運營與數據驅動決…

面試 總結(1)

面試總結 一、spring相關 1. Spring Security角色管理實現 在智慧種植蟲害識別系統中&#xff0c;我實現了農戶端和企業端的雙角色權限控制&#xff0c;這一部分是這樣實現的&#xff1a; MySQL 表時設計區分農戶和企業的角色表與權限表。登錄時&#xff0c;JWT 令牌包含用戶 I…

串與數組:從字符處理到多維存儲的數據結構詳解

串&#xff08;字符串&#xff09;和數組是數據結構中的兩個重要分支&#xff0c;它們在程序設計中承擔著不同但互補的角色。串專門處理字符數據&#xff0c;而數組則提供了多維數據的存儲和訪問機制。本文將深入探討這兩種數據結構的理論基礎、實現方法和核心算法。 文章目錄1…

面試之JVM

類的生命周期 加載、鏈接、初始化&#xff08;是類的初始化&#xff09;、使用&#xff08;對象的初始化&#xff09;、卸載&#xff08;GC&#xff09; 鏈接&#xff1a;驗證、準備、解析 類加載 JDK9的升級點&#xff1a;擴展類加載器改成了平臺類加載器。 java中很多的包分…

webpack開發模式與生產模式(webpack --mode=development/production“, )

webpack開發模式與生產模式的區別webpack的development&#xff08;開發模式&#xff09;和production&#xff08;生產模式&#xff09;是兩種常見的構建環境配置&#xff0c;主要區別體現在構建速度、代碼優化和調試支持等方面。開發模式 (development)目標&#xff1a;注重開…

當自然語言遇上數據庫:Text2Sql.Net的MCP革命如何重新定義開發者與數據的交互方式

想象一下&#xff0c;在IDE中對AI助手說"幫我找出本月銷售額最高的前10個產品"&#xff0c;然后它不僅能理解你的意圖&#xff0c;還能直接生成并執行SQL查詢&#xff0c;返回準確結果——這不是科幻&#xff0c;而是Text2Sql.Net的MCP集成帶來的現實。 &#x1f3af…

2025流程圖模板和工具深度評測:AI如何提升繪圖效率80%?

引言&#xff1a;流程圖模板的價值革命 在數字化辦公的浪潮中&#xff0c;流程圖已從單純的"業務說明工具"進化為跨部門協作的"視覺語言"。據智研咨詢2025年報告顯示&#xff0c;規范使用流程圖模板可使團隊溝通效率提升40%&#xff0c;錯誤率降低58%。無…

WebSocket實時通信系統——js技能提升

2. WebSocket實時通信系統 功能概述 實現完整的WebSocket通信系統&#xff0c;支持實時消息推送、連接管理、心跳檢測和自動重連。 技術難點 WebSocket連接生命周期管理消息序列化和反序列化心跳機制和連接保活錯誤處理和重連策略多組件狀態同步 實現思路 2.1 WebSocket管理器 …

Spring AI 入門指南:三步將AI集成到Spring Boot應用

無需深入AI底層實現&#xff0c;Java開發者也能快速構建智能應用本文將介紹如何使用 Spring AI 在 Spring Boot 項目中快速集成 AI 能力。通過三步操作——添加依賴、配置 API 憑證和編寫調用代碼&#xff0c;Java 開發者可以輕松構建 AI 應用。一、Spring AI 簡介Spring AI 是…

OOM問題排查思路及解決方案

OOM問題原因&#xff1a; 根本原因是創建的對象數量超過JVM堆內存容量&#xff0c;且這些對象無法被GC回收場景&#xff1a; 1.本地緩存了用戶態&#xff0c;用戶量急劇上升導致內存溢出&#xff0c;如使用HashMap本地緩存10萬用戶數據&#xff0c;每 個用戶對象約2KB&#xf…

梨花教育暖心鵬城:深圳市養老護理院里“時光綻放”,用聲音點亮銀發精神之光

2025年8月24日&#xff0c;在深圳這座充滿活力與夢想的城市&#xff0c;一場溫暖人心的公益活動在深圳市養老護理院溫情上演。梨花教育策劃并組織了“梨花?時光綻放”公益活動&#xff0c;旨在通過聲音的魅力&#xff0c;為市養老護理院的老人們送去關懷與歡樂&#xff0c;豐富…

力扣100+補充大完結

力扣100分類一、Java基礎代碼模板1. 基礎輸入輸出模板import java.util.Scanner;class Solution {public static int linkedListOperation() {// 鏈表操作實現return 0;}public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.next…

SSM從入門到實戰:3.3 SpringMVC數據綁定與驗證

&#x1f44b; 大家好&#xff0c;我是 阿問學長&#xff01;專注于分享優質開源項目解析、畢業設計項目指導支持、幼小初高的教輔資料推薦等&#xff0c;歡迎關注交流&#xff01;&#x1f680; &#x1f4d6; 本文概述 本文是SSM框架系列SpringMVC基礎篇的第三篇&#xff0…

ctfshow_萌新web16-web20-----文件包含日志注入

_萌新web16解開md5?c36d_萌新web17-----文件包含禁用了php關鍵字&#xff0c;這個題禁了遠程文件包含,進行日志注入發現日志中有user-agent信息&#xff0c;因此我們可以在user-agent中寫入木馬抓包burpsuitUser-agent:<?php eval($_POST[cmd])?>抓包然后連接蟻劍_萌新…

Flink的CheckPoint與SavePoint

Flink的Checkpoint&#xff08;檢查點&#xff09;和Savepoint&#xff08;保存點&#xff09;是兩種不同的狀態快照機制&#xff0c;主要區別如下&#xff1a;1. ?Checkpoint??核心功能?&#xff1a;周期性觸發的容錯機制&#xff0c;用于故障恢復時保證狀態一致性57。?觸…

Ansible 自動化運維工具:介紹與完整部署(RHEL 9)

Ansible 自動化運維工具&#xff1a;介紹與完整部署&#xff08;RHEL 9&#xff09;Ansible 的介紹與安裝 一、自動化運維的必要性 傳統手動運維依賴圖形/命令行界面、檢查清單或記憶執行任務&#xff0c;存在以下核心問題&#xff1a; 易出錯&#xff1a;易跳過步驟或執行錯誤…

構建生產級 RAG 系統:從數據處理到智能體(Agent)的全流程深度解析

文章目錄一、 整體架構設計&#xff1a;邁向智能體&#xff08;Agent&#xff09;驅動的 RAG二、 數據準備與預處理&#xff1a;構建高質量知識庫2.1 數據加載與初步提取2.2 多策略分塊 (Multi-Strategy Chunking)邏輯分塊&#xff1a;按故障章節和關鍵說明傳統分塊&#xff1a…

Duplicate Same Files Searcher v10.7.0,秒掃全盤重復檔,符號鏈接一鍵瘦身

[軟件名稱]: Duplicate Same Files Searcher v10.7.0 [軟件大小]: 3.3 MB [軟件大小]: 夸克網盤 | 百度網盤 軟件介紹 Duplicate Same Files Searcher&#xff08;重復文件搜索&#xff09;是一款強大且專業的重復文件查找與清理工具。通過使用該軟件&#xff0c;用戶可以方…

C/C++ 數據結構 —— 樹(2)

? &#x1f381;個人主頁&#xff1a;工藤新一 ? &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; ? &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 ? &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章…