Java之Stream其二

文章目錄

  • 5,Optional
    • 5.1,概述
    • 5.2,使用
      • 5.2.1,創建對象
      • 5.2.2,安全消費值
      • 5.2.3,獲取值
      • 5.2.4,安全獲取值
      • 5.2.5,過濾
      • 5.2.6,判斷
      • 5.2.7,數據轉換
  • 6,方法引用
    • 6.1 推薦用法
    • 6.2 基本格式
    • 6.3 語法詳解(了解)
      • 6.3.1 引用類的靜態方法
      • 6.3.2 引用對象的實例方法
      • 6.3.3 引用類的實例方法
      • 6.3.4 構造器引用
  • 7,高級用法
    • 7.1,基本數據類型優化
    • 7.2,并行流

5,Optional

5.1,概述

? 我們在編寫代碼的時候出現最多的就是空指針異常。所以在很多情況下我們需要做各種非空的判斷。

? 例如:

        Author author = getAuthor();if(author!=null){System.out.println(author.getName());}

? 尤其是對象中的屬性還是一個對象的情況下。這種判斷會更多。

? 而過多的判斷語句會讓我們的代碼顯得臃腫不堪。

? 所以在JDK8中引入了Optional,養成使用Optional的習慣后你可以寫出更優雅的代碼來避免空指針異常。

? 并且在很多函數式編程相關的API中也都用到了Optional,如果不會使用Optional也會對函數式編程的學習造成影響。

5.2,使用

5.2.1,創建對象

? Optional就好像是包裝類,可以把我們的具體數據封裝Optional對象內部。然后我們去使用Optional中封裝好的方法操作封裝進去的數據就可以非常優雅的避免空指針異常。

? 我們一般使用Optional靜態方法ofNullable來把數據封裝成一個Optional對象。無論傳入的參數是否為null都不會出現問題。

Author author = getAuthor();
Optional<Author> authorOptional = Optional.ofNullable(author);

? 你可能會覺得還要加一行代碼來封裝數據比較麻煩。但是如果改造下getAuthor方法,讓其的返回值就是封裝好的Optional的話,我們在使用時就會方便很多。

? 而且在實際開發中我們的數據很多是從數據庫獲取的。Mybatis從3.5版本可以也已經支持Optional了。我們可以直接把dao方法的返回值類型定義成Optional類型,MyBastis會自己把數據封裝成Optional對象返回。封裝的過程也不需要我們自己操作。

? 如果你確定一個對象不是空的則可以使用Optional靜態方法of來把數據封裝成Optional對象。

Author author = new Author();
Optional<Author> authorOptional = Optional.of(author);

? 但是一定要注意,如果使用of的時候傳入的參數必須不為null。(嘗試下傳入null會出現什么結果)

? 如果一個方法的返回值類型是Optional類型。而如果我們經判斷發現某次計算得到的返回值為null,這個時候就需要把null封裝成Optional對象返回。這時則可以使用Optional靜態方法empty來進行封裝。

    Optional.empty()

?

? 所以最后你覺得哪種方式會更方便呢?ofNullable

5.2.2,安全消費值

? 我們獲取到一個Optional對象后肯定需要對其中的數據進行使用。這時候我們可以使用其ifPresent方法對來消費其中的值。

? 這個方法會判斷其內封裝的數據是否為空,不為空時才會執行具體的消費代碼。這樣使用起來就更加安全了。

? 例如,以下寫法就優雅的避免了空指針異常。

Optional<Author> authorOptional = Optional.ofNullable(getAuthor());authorOptional.ifPresent(author -> System.out.println(author.getName()));

5.2.3,獲取值

? 如果我們想獲取值自己進行處理可以使用get()方法獲取,但是不推薦。因為當Optional內部的數據為空的時候會出現異常。

5.2.4,安全獲取值

? 如果我們期望安全的獲取值。我們不推薦使用get方法,而是使用Optional提供的以下方法。

  • orElseGet

    獲取數據并且設置數據為空時的默認值。如果數據不為空就能獲取到該數據。如果為空則根據你傳入的參數來創建對象作為默認值返回。

    Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
    Author author1 = authorOptional.orElseGet(() -> new Author());
    
  • orElseThrow

    獲取數據,如果數據不為空就能獲取到該數據。如果為空則根據你傳入的參數來創建異常拋出。

    Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
    try {Author author = authorOptional.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("author為空"));System.out.println(author.getName());
    } catch (Throwable throwable) {throwable.printStackTrace();
    }
    

5.2.5,過濾

? 我們可以使用filter方法對數據進行過濾。如果原本是有數據的,但是不符合判斷,也會變成一個無數據的Optional對象。

        Optional<Author> authorOptional = Optional.ofNullable(getAuthor());authorOptional.filter(author -> author.getAge()>100).ifPresent(author -> System.out.println(author.getName()));

5.2.6,判斷

? 我們可以使用isPresent方法進行是否存在數據的判斷。如果為空返回值為false,如果不為空,返回值為true。但是這種方式并不能體現Optional的好處,更推薦使用ifPresent方法

Optional<Author> authorOptional = Optional.ofNullable(getAuthor());if (authorOptional.isPresent()) {System.out.println(authorOptional.get().getName());
}

5.2.7,數據轉換

? Optional還提供了map可以讓我們的對數據進行轉換,并且轉換得到的數據也還是被Optional包裝好的,保證了我們的使用安全。

例如我們想獲取作家的書籍集合。

    private static void testMap() {Optional<Author> authorOptional = getAuthorOptional();Optional<List<Book>> optionalBooks = authorOptional.map(author -> author.getBooks());optionalBooks.ifPresent(books -> System.out.println(books));}

6,方法引用

6.1 推薦用法

? 我們在使用lambda時不需要考慮什么時候用方法引用,用哪種方法引用,方法引用的格式是什么。我們只需要在寫完lambda方法發現方法體只有一行代碼,并且是方法的調用時使用快捷鍵嘗試是否能夠轉換成方法引用即可。

6.2 基本格式

類名或者對象名::方法名

6.3 語法詳解(了解)

6.3.1 引用類的靜態方法

其實就是引用類的靜態方法

格式

類名::方法名

使用前提

? 如果我們在重寫方法的時候,方法體中只有一行代碼,并且這行代碼是調用了某個類的靜態方法,并且我們把要重寫的抽象方法中所有的參數都按照順序傳入了這個靜態方法中,這個時候我們就可以引用類的靜態方法。

例如:

如下代碼就可以用方法引用進行簡化

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();authorStream.map(author -> author.getAge()).map(age->String.valueOf(age));

注意,如果我們所重寫的方法是沒有參數的,調用的方法也是沒有參數的也相當于符合以上規則。

優化后如下:

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();authorStream.map(author -> author.getAge()).map(String::valueOf);

6.3.2 引用對象的實例方法

格式

對象名::方法名

使用前提

? 如果我們在重寫方法的時候,方法體中只有一行代碼,并且這行代碼是調用了某個對象的成員方法,并且我們把要重寫的抽象方法中所有的參數都按照順序傳入了這個成員方法中,這個時候我們就可以引用對象的實例方法

例如:

傳進去一個參數name,并且按順序傳入了append的sb的成員方法中。

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName()).forEach(name->sb.append(name));

優化后:

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName()).forEach(sb::append);

6.3.3 引用類的實例方法

格式

類名::方法名

使用前提

? 如果我們在重寫方法的時候,方法體中只有一行代碼,并且這行代碼是調用了第一個參數的成員方法,并且我們把要重寫的抽象方法中剩余的所有的參數都按照順序傳入了這個成員方法中,這個時候我們就可以引用類的實例方法。

例如:

調用了第一個參數str,且重寫的抽象方法use剩余參數start和length按照順序依次傳入成員方法substring()中。

interface UseString{String use(String str,int start,int length);
}public static String subAuthorName(String str, UseString useString){int start = 0;int length = 1;return useString.use(str,start,length);
}
public static void main(String[] args) {subAuthorName("三更草堂", new UseString() {@Overridepublic String use(String str, int start, int length) {return str.substring(start,length);}});}

優化后如下:

public static void main(String[] args) {subAuthorName("三更草堂", String::substring);}

6.3.4 構造器引用

如果方法體中的一行代碼是構造器的話就可以使用構造器引用。

格式

類名::new

使用前提

? 如果我們在重寫方法的時候,方法體中只有一行代碼,并且這行代碼是調用了某個類的構造方法,并且我們把要重寫的抽象方法中的所有的參數都按照順序傳入了這個構造方法中,這個時候我們就可以引用構造器。

例如:

List<Author> authors = getAuthors();
authors.stream().map(author -> author.getName()).map(name->new StringBuilder(name)).map(sb->sb.append("-三更").toString()).forEach(str-> System.out.println(str));

優化后:

List<Author> authors = getAuthors();
authors.stream().map(author -> author.getName()).map(StringBuilder::new).map(sb->sb.append("-三更").toString()).forEach(str-> System.out.println(str));

7,高級用法

7.1,基本數據類型優化

? 我們之前用到的很多Stream的方法由于都使用了泛型。所以涉及到的參數和返回值都是引用數據類型。

? 即使我們操作的是整數小數,但是實際用的都是他們的包裝類。JDK5中引入的自動裝箱和自動拆箱讓我們在使用對應的包裝類時就好像使用基本數據類型一樣方便。但是你一定要知道裝箱和拆箱肯定是要消耗時間的。雖然這個時間消耗很下。但是在大量的數據不斷的重復裝箱拆箱的時候,你就不能無視這個時間損耗了。

? 所以為了讓我們能夠對這部分的時間消耗進行優化。Stream還提供了很多專門針對基本數據類型的方法。

? 例如:mapToInt,mapToLong,mapToDouble,flatMapToInt,flatMapToDouble等。

List<Author> authors = getAuthors();
authors.stream().map(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);authors.stream().mapToInt(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);

優化后:

使用.mapToInt(author -> author.getAge())后,流當中的元素都是int類型了,節省了時間。

authors.stream().mapToInt(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);

7.2,并行流

當流中有大量元素時,我們可以使用并行流去提高操作的效率。其實并行流就是把任務分配給多個線程去完全。如果我們自己去用代碼實現的話其實會非常的復雜,并且要求你對并發編程有足夠的理解和認識。而如果我們使用Stream的話,我們只需要修改一個方法的調用就可以使用并行流來幫我們實現,從而提高效率。

  • parallel() 將順序流轉換為并行流,使得后續的操作(如 peekfilterreduce)可能在多個線程中并行執行。
private static void test() {Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);Integer sum = stream.parallel().peek(new Consumer<Integer>() {@Overridepublic void accept(Integer num) {System.out.println(num+Thread.currentThread().getName());}}).filter(num -> num > 5).reduce((result, ele) -> result + ele).get();System.out.println(sum);
}

執行結果:

7main
2ForkJoinPool.commonPool-worker-11
8ForkJoinPool.commonPool-worker-4
9ForkJoinPool.commonPool-worker-18
6main
1ForkJoinPool.commonPool-worker-11
5ForkJoinPool.commonPool-worker-29
4ForkJoinPool.commonPool-worker-4
10ForkJoinPool.commonPool-worker-18
3ForkJoinPool.commonPool-worker-25
40

為什么會打印多次num+mian?

主線程也被分配到任務,main 線程參與了并行流的處理,主線程處理了元素 7 和 6,說明這兩個元素被分配給了主線程執行。

并行流執行流程示例:

  1. 主線程將 10 個元素分成 4 個子任務(例如每組 2~3 個元素)。
  2. 工作線程 worker-1worker-4 各領取一個子任務。
  3. 主線程發現還有剩余元素(如最后 2 個),直接處理它們。
  4. 所有線程并行執行 peekfilterreduce 操作。

也可以通過parallelStream直接獲取并行流對象。

parallelStream() 是集合(如 ListSet 等)提供的一個方法,用于創建并行流。它與 stream().parallel() 的效果相同,但寫法更簡潔。并行流的核心特點是將流的處理任務分解到多個線程上并行執行,從而提高處理大量數據時的性能。

List<Author> authors = getAuthors();
authors.parallelStream().map(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);

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

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

相關文章

一般芯片電氣特性中Flash參數達到其最大值的條件是什么?

芯片電氣特性中標注的最大值&#xff08;比如 Data Flash 擦除時間的最大值&#xff09;&#xff0c;代表在最惡劣但仍在規格書定義的工作條件范圍內的情況下&#xff0c;該參數可能達到的最差值。達到這個最大值通常是由多個最壞情況因素組合造成的。 對于 Data Flash 擦除時間…

python中正則中的split方法、sub方法、finditer方法、compile方法、match對象

正則常見方法梳理 split方法 將一個字符串按照正則表達式匹配結果進行分割,返回結果是列表類型。 pattern:正則表達式的字符串或原生字符串表示string:待匹配字符串maxsplit:最大分割數,剩余部分最為最后一個元素輸出flags:正則表達式使用時候的控制標記 re模塊的spli…

Pytorch中張量的索引和切片使用詳解和代碼示例

PyTorch 中張量索引與切片詳解 使用前先導入&#xff1a; import torch1.基礎索引&#xff08;類似 Python / NumPy&#xff09; 適用于低維張量&#xff1a;x[i]、x[i, j] x torch.tensor([[10, 11, 12],[13, 14, 15],[16, 17, 18]])print(x[0]) # 第0行: tensor([10…

北京-4年功能測試2年空窗-報培訓班學測開-第五十一天

行叭&#xff0c;今天復習第一天&#xff0c;狀態效率&#xff0c;差我發現&#xff0c;一旦換了新環境/知識&#xff0c;我就需要重新調整狀態&#xff0c;少則一兩天&#xff0c;多則一周多。從周日起就很迷茫&#xff0c;哪怕昨天老師講了簡歷與面試&#xff0c;我也清楚地知…

虛擬現實的鏡廊:當技術成為存在之繭

傍晚&#xff0c;摘下VR頭盔的瞬間&#xff0c;房間里未關的臺燈竟顯得刺眼。指尖劃過光滑的塑料外殼&#xff0c;溫熱的機體還在微微震動&#xff0c;如同某種活物的呼吸。窗外城市的光污染在玻璃上暈染成片&#xff0c;而我的視網膜里仍殘留著方才的極光&#xff1a;挪威峽灣…

OSPF過濾

首先需要復習一個點&#xff1a;ACL最終隱含規則不同&#xff1a;如果acl匹配的是流量&#xff0c;則默認是運行所有如果acl匹配的是路由&#xff0c;則默認是拒絕所有OSPF過濾&#xff1a; 1.路由過濾1.LSA可以正常學習&#xff0c;但是不會使用LSA計算路由[AR1]acl 2000[AR1-…

OneCode 3.0 VFS客戶端驅動(SDK)技術解析:從架構到實戰

引言 在分布式系統架構中&#xff0c;高效的文件管理一直是開發者面臨的核心挑戰。OneCode 3.0作為新一代微內核引擎&#xff0c;其VFS&#xff08;虛擬文件系統&#xff09;模塊通過客戶端驅動(SDK)提供了統一的文件操作抽象&#xff0c;屏蔽了底層存儲細節&#xff0c;為開發…

@Reusable-組件復用

Reusable組件復用概述&#xff1a;ArkUI布局中&#xff0c;將自定義組件從組件樹上移除后放入緩存池&#xff0c;后續在創建相同類型的組件節點時&#xff0c;直接復用緩存池中的組件對象。ArkUI中使用Reusable裝飾器以實現自定義組件的復用。常見的組件復用場景是當有大量數據…

黑馬點評系列問題之p63unlock.lua不知道怎么整

問題描述&#xff1a;這個位置的這個unlock.lua文件是怎么生成的。老師給的不是很清楚。解決右鍵單擊resources。如圖輸入回車&#xff0c;然后界面的上方&#xff0c;大概是在這個位置&#xff0c;會有讓你引入這個依賴的選項&#xff0c;我的已經沒有了。他會出來大概三個選項…

Python爬蟲實戰:研究Python-Markdown庫相關技術

1. 引言 在當今信息爆炸的時代,網絡上存在著大量有價值的技術文章。對于技術人員來說,如何高效地收集、整理和保存這些文章是一個重要的問題。爬蟲技術可以幫助我們自動從網絡上獲取所需的文章內容,而 Markdown 作為一種輕量級標記語言,因其簡潔的語法和良好的兼容性,成為…

JAVA經典單例模式

前言單例模式&#xff08;Singleton Pattern&#xff09;是一種創建型設計模式&#xff0c;確保一個類僅有一個實例&#xff0c;并提供全局訪問點。它在需要控制資源&#xff08;如數據庫連接、配置管理&#xff09;或避免重復創建對象的場景中廣泛應用。一&#xff0c;核心概念…

20250715問答課題-基于BERT與混合檢索問答系統

1. 引言構建一個基于BERT與混合檢索策略的智能問答系統&#xff0c;通過深度學習與傳統檢索技術的融合&#xff0c;解決了心法領域知識檢索中的三個關鍵問題&#xff1a;(1)專業術語的語義理解不足&#xff1b;(2)問答匹配精度低&#xff1b;(3)檢索結果多樣性差。2. 方法2.1. …

面向對象與面向過程、函數式編程

面向對象與面向過程、函數式編程 1. 面向過程編程&#xff08;Procedure-Oriented Programming&#xff09; 面向過程編程將程序視為一系列函數的集合&#xff0c;數據和操作數據的函數是分離的。在 Vue 3 中&#xff0c;這種風格通常表現為使用組合式 API&#xff08;Composit…

基于大數據的淘寶用戶行為數據分析系統的設計與實現

開發環境開發語言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服務器&#xff1a;tomcat7 數據庫&#xff1a;mysql5.7&#xff08;一定要5.7版本&#xff09; 數據庫工具&#xff1a;Navicat11 開發軟件&#xff1a;eclipse/myeclipse/idea Maven…

視頻人臉處理——人臉面部動作提取

文章目錄基于openface實現的技術方案windows環境下使用1. 安裝依賴軟件2. 下載OpenFace代碼3. 編譯OpenFace4. 提取面部動作單元5.選擇提取目標方案liunx環境下使用安裝與配置使用 OpenFace 提取面部動作單元應用場景基于py-feat實現的方案1. 從HuggingFace下載模型并設置Detec…

【Docker基礎】Dockerfile構建與運行流程完全指南:從原理到實踐優化

目錄 引言 1 docker build命令參數詳解 1.1 命令概述 1.2 常用參數詳解 1.2.1 -t, --tag 1.2.2 -f, --file 1.2.3 --build-arg 1.2.4 --no-cache 1.2.5 --pull 1.3 構建流程圖解 2 構建上下文&#xff08;Context&#xff09;優化技巧 2.1 構建上下文定義 2.2 優化…

StarRocks Community Monthly Newsletter (Jun)

版本動態 v3.5.0 存算分離&#xff1a;支持生成列、主鍵表重建索引&#xff1b;大規模導入邏輯優化&#xff0c;降低小文件數量。 數據湖分析&#xff1a;Beta 支持 Iceberg 視圖創建與修改&#xff1b;支持 Iceberg REST Catalog 嵌套命名空間&#xff1b; 性能提升與查詢優…

HDMI接口 vs. DisplayPort接口:電競玩家該如何選擇更優?

在搭建游戲主機或電競PC時&#xff0c;顯示器接口的選擇&#xff08;HDMI vs. DP&#xff09;會直接影響畫質、刷新率和延遲表現。本文將從分辨率、刷新率、可變刷新率&#xff08;VRR&#xff09;、帶寬、兼容性等角度對比&#xff0c;幫你選出最適合游戲的接口。1. 基礎對比&…

論文筆記:Learning Cache Replacement with CACHEUS

2021 USENIX GitHub - sylab/cacheus: The design and algorithms used in Cacheus are described in this USENIX FAST21 paper and talk video: https://www.usenix.org/conference/fast21/presentation/rodriguez Learning Cache Replacement with CACHEUS 1 intro 基于…

極致cms多語言建站|設置主站默認語言與設置后臺固定語言為中文

小記 很長時間沒有建站了,最近有需求所以又回爐了&#xff0c;使用的極致cms 極致cms幫助文檔 | 極致CMS幫助文檔 由于很長時間沒做&#xff0c;又遇到了之前碰到的兩個問題&#xff0c;憑借經驗和記憶還是處理掉了 1.當網站前臺使用?len或?lzh來切換語言時&#xff0c;管…