Java -> Stream入門

来源:https://www.cnblogs.com/buzuweiqi/archive/2022/08/26/16616100.html
-Advertisement-
Play Games

學習Stream的目的 函數式編程漸漸變成主流,為了看懂同事的代碼。 相對於傳統的編程方式,代碼更為簡潔清晰易懂。 使得併發編程變得如此簡單。 有效的避免了代碼嵌套地獄。(見樣例) if (條件1) { if (條件2) { if (條件3) { // 再嵌套下去都快見到Diablo了。 } } } ...


學習Stream的目的

  • 函數式編程漸漸變成主流,為了看懂同事的代碼。

  • 相對於傳統的編程方式,代碼更為簡潔清晰易懂。

  • 使得併發編程變得如此簡單。

  • 有效的避免了代碼嵌套地獄。(見樣例)

    if (條件1) {
        if (條件2) {
            if (條件3) {
                // 再嵌套下去都快見到Diablo了。
            }
        }
    }
    

Stream的特點

  • 不修改數據源:任何對於Stream對象的操作都不會修改數據源的數據。
  • 延遲執行:中間操作只是對於一系列操作細節的定義,而非執行。只有在終端操作被調用的同時執行中間操作。
  • 可消費:任何一個Stream對象執行了終端操作後都將不可再利用。只能操作由數據源生成的新的Stream。

Stream的分類

  • 串列流:單項環境下的Stream,基礎。

    List.of().stream();
    
  • 並行流:多線程環境下的Stream,重點難點。本文中未涉及。

    List.of().parallelStream();
    

Stream對象的創建

總共有三種方式:

  • 經由集合對象創建

    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();
    
  • 經由數組對象創建(兩種)

    String[] strs = new String[10];
    // 將數組所有元素裝入stream
    Stream<String> stream1 = Arrays.stream(strs);
    // 將數組指定區間的元素裝入stream
    Stream<String> stream2 = Arrays.stream(strs, 1, 7);
    
  • 使用Stream的靜態方法創建(三種)

    // 由單個元素創建Stream,元素不允許為null
    Stream<String> stream1 = Stream.of("Test");
    // 由單個元素創建stream,元素允許為null
    Stream<String> stream2 = Stream.ofNullable(null);
    // 由多個元素創建stream,內部其實調用的是Arrays.stream(T[] array)
    Stream<String> stream3 = Stream.of("Test1", "Test2", "Test3");
    

方法的分類

  • 中間操作:根據調用的方法,返回各種各樣的stream對象。傳入的各種Lambda只是修改了該對象中對應方法的定義,而非執行。
  • 終端操作:執行終端操作的方法,並且其間也執行中間操作對應的方法。

常用方法(入門)

中間操作

distinct

方法簽名:Stream<T> distinct()
作用:返回一個去重後的Stream。

List<String> list = List.of("1", "1");
list.stream().distinct()
    .forEach(t -> System.out.println(t)); // 輸出:1

filter

方法簽名:Stream<T> filter(Predicate<? super T> predicate)
作用:返回一個由滿足predicate條件的元素構成的Stream。

List<Integer> list = List.of(1, 3, 5);
list.stream().filter(t -> t >= 3)
    .forEach(t -> System.out.println(t)); // 輸出:3, 5

sorted

因為sorted存在兩種重載,並且在jdk源碼的實現並不相同,所以我們分開討論。

方法簽名:Stream<T> sorted()
作用:通過調用T類型重寫Comparable介面的compareTo方法排序,返回排序後的Stream。

// 此處省略了一些java文件定義的結構,請著眼於一下核心代碼
// NG例, 不實現Comparable介面
class MyInteger {
    int value;
    MyInteger(int value) {
    	this.value = value;
    }
}
List<MyInteger> list = new ArrayList<>();
list.add(new MyInteger(4));
list.add(new MyInteger(1));
list.add(new MyInteger(3));
list.stream().sorted() // 不報錯
    .forEach(t -> System.out.println(t.value)); // ClassCastException:不能被強轉成Comparable類型

// OK例, 實現Comparable介面(Integer實現了Comparable介面)
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted()
    .forEach(t -> System.out.println(t)); // 輸出:1 3 4

方法簽名:Stream<T> sorted(Comparator<? super T> comparator)
作用:通過調用傳入的comparator的compare方法排序,返回排序後的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted((o1, o2) -> o2 - o1) // 傳入一個比較器的實現
    .forEach(t -> System.out.println(t.value)); // 輸出:4 3 1

skip

方法簽名:Stream<T> skip(long n)
作用:返回一個不包含前n項的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().skip(2) // 跳過前兩個元素
    .forEach(t -> System.out.println(t.value)); // 輸出:3

limit

方法簽名:Stream<T> limit(long n)
作用:返回一個包含前n項的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().limit(2) // 跳過前兩個元素
    .forEach(t -> System.out.println(t.value)); // 輸出:4 1

peek

方法簽名:Stream<T> peek(Consumer<? super T> action)
作用:執行消費操作,返回原Stream。雖然有消費操作,但是Stream的狀態並不會改變。並不會真正消費Stream這一特點是的peek方法常用於調試。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Stream<Integer> stream = list.stream();
stream.peek(t -> System.out.println(t)); // 輸出:4 1 3, 並且不消費stream
stream.forEach(t -> System.out.println(t)); // 輸出:4 1 3, 並且消費stream(消費後stream不可再次使用)
stream.forEach(t -> System.out.println(t)); // IllegalStateException:stream已經被操作或關閉

map

方法簽名:Stream<T> map(Function<? super T, ? extends R> mapper)
作用:將原Stream中的所有元素類型從T轉化為R(不是強轉,是通過一些操作得到R類型),返回封裝R類型元素的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().map(t -> String.valueOf(t)) // 將元素都轉換成String
    .forEach(t -> System.out.println(t)); // 輸出:4 1 3

flatMap

方法簽名:Stream<T> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
作用:將原Stream中的所有元素類型從T轉化為R,返回Stream<R>。與map的主要區別在於,適配一對多的數據類型。比如,類型T中存在一個List<String>,使用map返回一個Stream<List<String>>,而是用flatMap則返回一個Stream<String>,實現一對多的映射。

List<Integer[]> list = new ArrayList<>();
list.add(new Integer[] {1, 2, 3});
list.add(new Integer[] {4, 5, 3});
list.stream().flatMap(t -> Stream.of(t)) // 將各個數組中的元素都放入stream, 實現 1 → n 的轉換
    .forEach(t -> System.out.println(t)); // 輸出:1 2 3 4 5 3

終端操作

forEach

方法簽名:void forEach(Consumer<? super T> action)
作用:迭代消費Stream里的所有元素,比如列印,寫入文件,寫入DB等。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().forEach(t -> System.out.println(t)); // 輸出:4 1 3

toArray

方法簽名:Object[] toArray()
作用:將Stream中的所有元素封裝成Object[]返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Object[] objects = list.stream().toArray(); // 與元素類型無關, 固定返回Object[]
Integer[] ints = (Integer[])objects; // 使用時你可能需要類型強轉

count

方法簽名:long count()
作用:返回Stream中的元素個數。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
long count = list.stream().count(); // 返回stream中的元素個數, 當前為3

findFirst

方法簽名:Optional<T> findFirst()
作用:Stream的第一個元素封裝在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> first = list.stream().findFirst(); // 返回stream中的第一個元素, 當前為4
/* 
	Optional類內容比較多所以現在不做贅述, 大家姑且就認為是個只能存放一個元素的容器就好,以後會開一個新的博文詳細為	大家講解用法
 */

anyMatch

方法簽名:boolean anyMatch(Predicate<? super T> predicate)
作用:當存在符合predicate條件的元素時返回true,否則返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().anyMatch(t -> t <= 1); // 當一個元素小於等於1時就返回true, 當前true

allMatch

方法簽名:boolean allMatch(Predicate<? super T> predicate)
作用:當所有元素都符合predicate條件時返回true,否則返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().allMatch(t -> t <= 1); // 當所有元素小於等於1時才返回true, 當前false

noneMatch

方法簽名:boolean noneMatch(Predicate<? super T> predicate)
作用:當所有元素都不符合predicate條件時返回true,否則返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().noneMatch(t -> t <= 1); // 當所有元素都不小於等於1時才返回true, 當前false

min

方法簽名:Optional<T> min(Comparator<? super T> comparator)
作用:按照傳入的比較器將最小的元素封裝在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> min = list.stream().min((o1, o2) -> o2 - o1); // 根據傳入的比較器實現返回最小值, 當前4
/*
	這個方法可以認為stream按照傳入的比較器排序, 返回排序後的第一個元素
 */

max

方法簽名:Optional<T> max(Comparator<? super T> comparator)
作用:按照傳入的比較器將最大的元素封裝在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> max = list.stream().max((o1, o2) -> o2 - o1); // 根據傳入的比較器實現返回最大值
/*
	這個方法可以認為stream按照傳入的比較器排序, 返回排序後的最後一個元素
 */

本文只討論了串列流的使用方法,對於並行流等進階的使用方法請參考 Java -> Stream進階(尚未更新)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.懸浮球與設備劉海的安全距離無論是橫屏還是豎屏,懸浮球距離有劉海的一邊會留出安全距離設備方向的上下兩邊,也有安全距離 2.貼邊吸附方向和距離懸浮球只能貼設備方向的左右兩邊,需要貼上下兩邊自行調整距離邊緣的數值自行調整 3.切換橫豎屏,懸浮球自適應懸浮球位置切換橫豎屏後,等比例轉換的。 4.隱藏和顯 ...
  • 摘要:在許多軟體系統的開發運行階段乃至整個生命周期中,軟體可變性都是其設計開發者所要面對的基本問題。 本文分享自華為雲社區《如何應對軟體可變性?這4種常用的方法肯定要知道。》,作者: 陳星亮|華為雲開天aPaaS專家。 軟體可變性(Software Variability)是指在一定上下文中一個軟體 ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是MCUXpresso IDE下設置代碼編譯優化等級的幾種方法。 最近公司晶元設計團隊正在開發一款全新的基於 Cortex-M33 內核的晶元,為了保證晶元性能達標,驗證團隊將 coremark 基準測試程式也當作了一個測試用例,而在 R ...
  • 01_Linux基礎-部署-VMware-Xshell-Xftp-內核-安迪比爾定理 博客🔗:https://blog.csdn.net/cpen_web CentOS開源 免費 ==CentOS是Linux里的開源免費版本== 一. 配置虛擬機 1. 新建虛擬機 2. 放 鏡像文件 鏡像文件其實 ...
  • Silver Efex Pro是您將使用的最先進的黑白照片插件。憑藉其獨特的演算法以及一系列用於亮度,對比度和放大白色等變化的工具和調整,Silver Efex Pro 3可以藉助最全面的暗房風格控制項來掌握黑白攝影藝術,為大家帶來了20種不同的黑白傳奇電影效果。 詳情:Silver Efex Pro ...
  • 想要全方位的實現HDR增強效果小編推薦使用HDR Efex Pro 2 Mac版,這是一款一款全新的高動態(HDR)成像解決方案,內置33種HDR效果,用戶可在右側HDR進行細節微調,強大簡便。 詳情:HDR Efex Pro 2 for mac(HDR濾鏡軟體) Hdr Efex Pro2是一款全 ...
  • 很多小伙伴不知道Color Efex Pro 4是用來幹嘛的,小編給大家介紹一下,Color Efex Pro 4 for Mac全球最全面,最有創意的濾鏡組,用於色彩校正,潤飾和應用最令人驚嘆和最富想象力的攝影效果,釋放最大的創造力和想象力。 詳情:Color Efex Pro 4 for Mac ...
  • 1. 關聯關係 1.1 關聯關係概念說明 表與表之間的關係 : 1 對 1 1對多 多對多關係 ,通過主外鍵來實現。 外鍵在多的一方。比如員工和部門: 1個員工對應一個部門,一個部門可以有多個員工 要將表與表之間的關係:映射稱為 類與類之間的關係(準確的說應該是 對象和對象之間的關係 ) 一對一 夫 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...