【java8】stream學習筆記

来源:https://www.cnblogs.com/ldupup/archive/2022/08/08/16563355.html
-Advertisement-
Play Games

精華筆記: package:聲明包 作用:避免類的命名衝突 同包中的類不能同名,但不同包中的類可以同名 類的全稱:包名.類名,包名常常有層次結構 建議:包名所有字母都小寫 import:導入類 同包中的類可以直接訪問 不同包中的類不能直接訪問,若想訪問: 先import導入類再使用類 建議 類的全稱 ...


目錄

一、什麼是Stream

Stream是java8的新增特性,表示數據流。

二、Stream的特點

  1. 不存儲數據:流是基於數據源的對象,本身不存儲數據。
  2. 函數式編程:流的操作不會修改數據源。
  3. 延遲操作:流的很多操作如filtermap是延遲執行的,只有到了終點操作才會將操作順序執行。
  4. 可以解綁:對於無線數量的流,有些操作(如limit(n)findFirst())可以實現“短路操作”,訪問到有限的元素後就可以返回。
  5. 純消費:流只能被消費一次。如果使用完了一次流,仍然用這個流對象來操作時,會報異常。

串並行

所有的流操作都可以串列執行或者並行執行。除非顯示的創建並行流,否則預設創建串列流。

串列:Collection.stream()IntStream.range(int, int)

並行:Collection.parallelStream()、

通過parallel()方法可以將串列流轉換為並行流,sequential()方法將流轉換為串列流

干擾數據源

流可以從非線程安全的集合中創建。當流執行時,非併發的數據源不應該改變,否則會拋出java.util.ConcurrentModificationException異常。

無狀態

大部分流的操作的參數都是函數式介面,可以使用Lambda表達式實現。它們用來描述用戶的行為,稱之為行為參數(behavioral parameters)。

如果這些行為參數有狀態,則流的操作的結果可能是不確定的,比如下麵的代碼:

下麵代碼在並行執行時,由於執行順序的不確定性,state.s的改變時機可能不同,導致多次執行時的結果不同

List<String> l = new ArrayList(Arrays.asList("one", "two", ……));
class State {
    boolean s;
}
final State state = new State();
Stream<String> sl = l.stream().map(e -> {
    if (state.s)
        return "OK";
    else {
        state.s = true;
        return e;
    } 
});
sl.forEach(System.out::println);

排序

某些流的返回元素是有確定順序的。這取決於它的數據源和中間操作。

比如List和Array創建的流是有序的,而HashSet創建的流是無序的。

sort()方法可以將流變得有序,而unordered()可以將流無序(不會打散元素)

當流有序時,如果用戶並不關心順序,可以使用unordered顯示的去掉流的有序約束,可以改善某些情況下的並行性能

三、創建Stream

常見創建流的方法:

  • 通過集合Collection的Stream()parallelStream():如list.parallelStream()、Arrays.asList(1,2,3).stream()。
  • 通過數組Arrays.stream(Object[])方法:如Arrays.stream(new int[]{1,2,3})。
  • 流的靜態方法:如:Stream.of(Object[])IntStream.range(int, int)Stream.iterate(Object, UnaryOperator)。
  • 隨機數流Random.ints()

四、中間操作

中間操作是延遲執行的,不會修改原始數據流,在終點操作開始時才會開始執行

1. distinct

根據流中元素的hashCode()equals()方法去除重覆元素

List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().distinct().forEach(System.out::print); // 123456
System.out.println();
list.forEach(System.out::print); // 12344456

2. filter

接收predicate,過濾數據

// 篩選出偶數
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().filter(e -> e % 2 == 0).forEach(System.out::print); // 24446

3. map

接收一個Function實例,重新印射數據

// 加1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().map(e -> e + 1).forEach(System.out::print); // 23455567

4. mapToDouble

類似map,不過結果一定要是Double類型。

類似的方法還有mapToInt(),mapToLong()

// 加1.1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().mapToDouble(e -> e + 1.1).forEach(System.out::println);
/*
2.1
3.1
4.1
5.1
5.1
5.1
6.1
7.1
*/
// 加1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().mapToDouble(e -> e + 1).forEach(System.out::println);
/*
2.0
3.0
4.0
5.0
5.0
5.0
6.0
7.0
*/

4. flatmap

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

將映射後的元素放在一個新的流中。

類似的方法還有flatMapToDoubleflatMapToIntflatMapToLong

List<String> list = Arrays.asList("1233", "2444", "562","78");
list.stream()
    .flatMap(e -> Arrays.stream(e.split("2")))
    .forEach(System.out::println);
/*
1
33

444
56
78
*/

5. limit

限制流中元素的數量。對於有序並行流,性能消耗更高

List<Integer> list = Arrays.asList(1, 2, 3, 4, 4, 4, 5, 6);
list.stream().limit(5).forEach(System.out::print); // 12344

6. skip

丟棄前n個元素,返迴流。

System.out.println("-----------------------");
list.stream().skip(6).forEach(System.out::println);
System.out.println("-----------------------");
list.stream().skip(8).forEach(System.out::println);
/*
7
5
-----------------------
-----------------------
*/

7. peek

接收一個Consumer,對元素做某些操作,但是並不會修改數據(對象數據可能會被修改)。一般用於debug

List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
list.stream().peek(System.out::print).count(); // 810975

8. sorted

將流中的元素按自然順序排序。可以自定義比較器。

System.out.println("升序: ");
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
list.stream().sorted().forEach(System.out::print);
System.out.println();
System.out.println("降序: ");
list.stream().sorted((x, y) -> y - x).forEach(System.out::print);
/*
升序: 
015789
降序: 
987510
*/

五、終點操作

1. Match

allMatch(Predicate p)anyMatch(Predicate p)noneMatch(Predicate p)三種方法。

返回boolean

List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
// allMatch 是否全部符合
System.out.println(list.stream().allMatch(x -> x > -1)); // true
System.out.println(list.stream().allMatch(x -> x > 1)); // false
// anyMatch 是否至少有一個符合
System.out.println(list.stream().anyMatch(x -> x == -1)); // false
System.out.println(list.stream().anyMatch(x -> x == 1)); // true
// noneMatch 是否全部不符合
System.out.println(list.stream().noneMatch(x -> x > 5)); // false
System.out.println(list.stream().noneMatch(x -> x > 9)); // true

2. count

返迴流中元素的數量。返回long

List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
System.out.println(list.stream().count()); // 6

3. collect

傳入Collectors中的介面實現,將流轉化為其他形式的數據。部分介面:

  • toListtoSet 轉化為list或set
  • counting 計數
  • reducing 化簡
  • maxByminBy 最大值最小值
  • summingInt 求和
  • joining 字元串連接
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);

// 轉化為list格式
List<Integer> res1 = list.stream().collect(Collectors.toList());

// 轉化為set格式
Set<Integer> res2 = list.stream().collect(Collectors.toSet());

4. find

有findFirst()和findAny()兩種。返回Optional對象

Optional<T> findFirst();
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
Optional<Integer> integer = list.stream().findFirst();
System.out.println(integer.get()); // 8

// findAny()對於串列流:一般返回第一個結果
integer = list.stream().findAny();
System.out.println(integer.get()); // 8

// findAny()對於並行流,多次執行會隨機返回結果
integer = list.parallelStream().findAny();
System.out.println(integer.get()); // 隨機列印

5. forEach

遍歷流中元素,執行指定操作

List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
List<Integer> res = new ArrayList<>();
list.stream().forEach(e -> res.add(e + 2));
System.out.println(list.toString());
// [10, 3, 2, 11, 9, 7]

6. max、min

最大值、最小值。返回Optional對象

將元素按比較器排序,然後min返回第一個數,max返回最後一個數

List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);

// 升序排序 015789
System.out.println(list.stream().min((x, y) -> x - y).get()); // 0
System.out.println(list.stream().max((x, y) -> x - y).get()); // 9

// 降序排序 987510
System.out.println(list.stream().min((x, y) -> y - x).get()); // 9
System.out.println(list.stream().max((x, y) -> y - x).get()); // 0

7. reduce

將元素數據結合後返回。

List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);

// 預設返回Optional類型數據
Optional<Integer> res1 = list.stream().reduce(Integer::sum);
System.out.println(res1.get());

// 指定返回數據類型為Integer
Integer res2 = list.stream().reduce(0, Integer::sum);
System.out.println(res2);

8. toArray()

將流中的元素保存到數組中

<A> A[] toArray(IntFunction<A[]> generator);
List<Integer> list = Arrays.asList(8, 1, 0, 9, 7, 5);
Integer[] ints = list.stream().map(e -> e + 1).toArray(Integer[]::new);
for (Integer integer : ints) {
    System.out.println(integer);
}
/*
9
2
1
10
8
6
*/

六、參考文檔

  1. https://colobu.com/2016/03/02/Java-Stream/
  2. https://juejin.cn/post/6844903646648336397#heading-9

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

-Advertisement-
Play Games
更多相關文章
  • 粒子動畫,顧名思義,就是頁面上存在大量的粒子構建而成的動畫。傳統的粒子動畫主要由 Canvas、WebGL 實現。 當然,不使用 HTML + CSS 的主要原因在於,粒子動畫通常需要較多的粒子,而如果使用 HTML + CSS 的話勢必需要過多的 DOM 元素,這也就導致了使用 HTML + CS ...
  • “基於介面而非實現編程”是一條比較抽象、泛化的設計思想,其的另一個表述是“基於抽象而非實現編程”。從這條設計思想中衍生的理解就是,越抽象、越頂層、越脫離具體某一實現的設計,越能提高代碼的靈活性,越能應對未來的需求變化。 ...
  • 一、 設計思維 的概念和發展背景 設計思維是一種以用戶為中心,為產品或服務的目標用戶解決定義不明確或未知問題的思維方式。自從認知科學家和諾貝爾獎獲得者 Herbert A. Simon 在他1969年的著作《人工科學》中首次提到設計思維的概念之後,世界在不斷發展的過程中為其原理貢獻了許多想法——史蒂 ...
  • python 爬取 博客園 接 螞蟻學pythonP5生產者消費者爬蟲數據重覆問題 先看訪問地址 訪問地址是https://www.cnblogs.com/#p2 但是實際訪問地址是https://www.cnblogs.com 說明其中存在貓膩;像這種我們給定指定頁碼,按理應該是 post 請求才 ...
  • 變數用法與特征 變數綁定 let a = "hello world" 為何不用賦值而用綁定呢(其實你也可以稱之為賦值,但是綁定的含義更清晰準確)?這裡就涉及 Rust 最核心的原則——所有權,簡單來講,任何記憶體對象都是有主人的,而且一般情況下完全屬於它的主人,綁定就是把這個對象綁定給一個變數,讓這個 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 微信登錄之前還需要瞭解OAuth2知識 前期準備 註冊微信開放平臺 郵箱激活 完善開發者資料(暫不支持個體用戶) 開發者資質認證:營業執照、1-2個工作如審批、300元 網站應用:最好是已經部署到伺服器上的項目,7個工作日審批 審核通過之後會有AppID和AppSecret兩個值 AppID: 申請 ...
  • 有時候我們需要把自己寫的類或者函數給別人使用,但又不希望讓別人知道具體的實現,那麼封裝成庫就是一個很好的方法。本文描述了怎麼去把一個C++程式封裝成一個靜態庫並且如何去使用這些靜態庫。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...