一文帶你入門Java Stream流,太強了

2020-12-14 計算機java編程

兩個星期以前,就有讀者強烈要求我寫一篇 Java Stream 流的文章,我說市面上不是已經有很多了嗎,結果你猜他怎麼說:「就想看你寫的啊!」你看你看,多麼蒼白的喜歡啊。那就「勉為其難」寫一篇吧,嘻嘻。

單從「Stream」這個單詞上來看,它似乎和 java.io 包下的 InputStream 和 OutputStream 有些關係。實際上呢,沒毛關係。Java 8 新增的 Stream 是為了解放程式設計師操作集合(Collection)時的生產力,之所以能解放,很大一部分原因可以歸功於同時出現的 Lambda 表達式——極大的提高了編程效率和程序可讀性。

Stream 究竟是什麼呢?

Stream 就好像一個高級的迭代器,但只能遍歷一次,就好像一江春水向東流;在流的過程中,對流中的元素執行一些操作,比如「過濾掉長度大於 10 的字符串」、「獲取每個字符串的首字母」等。

要想操作流,首先需要有一個數據源,可以是數組或者集合。每次操作都會返回一個新的流對象,方便進行鏈式操作,但原有的流對象會保持不變。

流的操作可以分為兩種類型:

1)中間操作,可以有多個,每次返回一個新的流,可進行鏈式操作。

2)終端操作,只能有一個,每次執行完,這個流也就用光光了,無法執行下一個操作,因此只能放在最後。

來舉個例子。

distinct() 方法是一個中間操作(去重),它會返回一個新的流(沒有共同元素)。

Stream<T> distinct();

count() 方法是一個終端操作,返回流中的元素個數。

longcount();

中間操作不會立即執行,只有等到終端操作的時候,流才開始真正地遍歷,用於映射、過濾等。通俗點說,就是一次遍歷執行多個操作,性能就大大提高了。

理論部分就扯這麼多,下面直接進入實戰部分。

01、創建流

如果是數組的話,可以使用 Arrays.stream() 或者 Stream.of() 創建流;如果是集合的話,可以直接使用 stream() 方法創建流,因為該方法已經添加到 Collection 接口中。

查看 Stream 源碼的話,你會發現 of() 方法內部其實調用了 Arrays.stream() 方法。

另外,集合還可以調用 parallelStream() 方法創建並發流,默認使用的是 ForkJoinPool.commonPool()線程池。

List<Long> aList = new ArrayList<>();Stream<Long> parallelStream = aList.parallelStream();

02、操作流

Stream 類提供了很多有用的操作流的方法,我來挑一些常用的給你介紹一下。

1)過濾通過 filter() 方法可以從流中篩選出我們想要的元素。

filter() 方法接收的是一個 Predicate(Java 8 新增的一個函數式接口,接受一個輸入參數返回一個布爾值結果)類型的參數,因此,我們可以直接將一個 Lambda 表達式傳遞給該方法,比如說 element -> element.contains("王") 就是篩選出帶有「王」的字符串。

forEach() 方法接收的是一個 Consumer(Java 8 新增的一個函數式接口,接受一個輸入參數並且無返回的操作)類型的參數,

類名 :: 方法名

是 Java 8 引入的新語法,System.out 返回 PrintStream 類,println 方法你應該知道是列印的。

stream.forEach(System.out::println);

相當於在 for 循環中列印,類似於下面的代碼:

for (String s : strs) {System.out.println(s);}

很明顯,一行代碼看起來更簡潔一些。來看一下程序的輸出結果:

王力宏

2)映射

如果想通過某種操作把一個流中的元素轉化成新的流中的元素,可以使用 map() 方法。

map() 方法接收的是一個 Function(Java 8 新增的一個函數式接口,接受一個輸入參數 T,返回一個結果 R)類型的參數,此時參數 為 String 類的 length 方法,也就是把 Stream<String> 的流轉成一個 Stream<Integer> 的流。

程序輸出的結果如下所示:

33 23

3)匹配

Stream 類提供了三個方法可供進行元素匹配,它們分別是:

anyMatch(),只要有一個元素匹配傳入的條件,就返回 true。allMatch(),只有有一個元素不匹配傳入的條件,就返回 false;如果全部匹配,則返回true。noneMatch(),只要有一個元素匹配傳入的條件,就返回 false;如果全部匹配,則返回 true。

因為「王力宏」以「王」字開頭,所以 anyMatchFlag 應該為 true;因為「周杰倫」、「王力宏」、「陶喆」、「林俊傑」的字符串長度都大於 1,所以 allMatchFlag 為 true;因為 4 個字符串結尾都不是「沉」,所以 noneMatchFlag 為 true。

程序輸出的結果如下所示:

truetrue true

4)組合

reduce() 方法的主要作用是把 Stream 中的元素組合起來,它有兩種用法:

Optional沒有起始值,只有一個參數,就是運算規則,此時返回 Optional。

T reduce(T identity, BinaryOperator有起始值,有運算規則,兩個參數,此時返回的類型和起始值類型一致。

來看下面這個例子。

運算規則可以是 Lambda 表達式(比如 (a, b) -> a + b),也可以是類名::方法名(比如 Integer::sum)。

程序運行的結果如下所示:

66 1212

0、1、2、3 在沒有起始值相加的時候結果為 6;有起始值 6 的時候結果為 12。

03、轉換流

既然可以把集合或者數組轉成流,那麼也應該有對應的方法,將流轉換回去——collect() 方法就滿足了這種需求。

toArray() 方法可以將流轉換成數組,你可能比較好奇的是 String[]::new,它是什麼東東呢?來看一下 toArray() 方法的源碼。

<A> A[] toArray(IntFunction<A[]> generator);

也就是說 String[]::new 是一個 IntFunction,一個可以產生所需的新數組的函數,可以通過反編譯字節碼看看它到底是什麼:

String[] strArray = (String[])list.stream().toArray((x$0) -> {returnnew String[x$0];});System.out.println(Arrays.toString(strArray));

也就是相當於返回了一個指定長度的字符串數組。

當我們需要把一個集合按照某種規則轉成另外一個集合的時候,就可以配套使用 map() 方法和 collect() 方法。

List<Integer> list1 = list.stream().map(String::length).collect(Collectors.toList());

通過 stream() 方法創建集合的流後,再通過 map(String:length) 將其映射為字符串長度的一個新流,最後通過 collect() 方法將其轉換成新的集合。

Collectors 是一個收集器的工具類,內置了一系列收集器實現,比如說 toList() 方法將元素收集到一個新的 java.util.List 中;比如說 toCollection() 方法將元素收集到一個新的 java.util.ArrayList 中;比如說 joining() 方法將元素收集到一個可以用分隔符指定的字符串中。

來看一下程序的輸出結果:

[周杰倫, 王力宏, 陶喆, 林俊傑][3, 3, 2, 3][周杰倫, 王力宏, 陶喆, 林俊傑]周杰倫, 王力宏, 陶喆, 林俊傑

04、鳴謝

好了,我親愛的讀者朋友,以上就是本文的全部內容了,是不是感覺 Stream 流實在是太強大了?原創不易,莫要白票,請你為本文點讚個吧,這將是我寫作更多優質文章的最強動力。

相關焦點

  • 巧用Java8中的Stream,讓集合操作飛起來!
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫作者:堅持就是勝利juejin.im/post/5d5e2616f265da03b638b28a簡介
  • JAVA8——JAVA成長之路
    你可能認為Java 8耗費了大量的時間才得以完成是為了實現了每個Java程式設計師所期待的特性。在這個小節裡,我們將會涉及到這些特性的大部分。下面是這個程序的輸出:更多詳情請參考官方文檔4.2 Stream最新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。
  • Java中的IO流,重點概念梳理
    如 FileReader)和處理流(是對一個 已存在的流的連接和封裝,通過所封裝的流的功能調用實現數據讀寫。如 BufferedReader。處理流的構造方法總是要 帶一個其他的流對象做參數。一個流對象經過其他流的多次包裝,稱為流的連結。)按照處理數據的單位:字節流和字符流。
  • JAVA8 新特性詳解
    函數式接口可以使用Lambda表達式,lambda表達式會被匹配到這個抽象方法上我們可以將lambda表達式當作任意只包含一個抽象方法的接口類型,確保你的接口一定達到這個要求,你只需要給你的接口添加 @FunctionalInterface 註解,編譯器如果發現你標註了這個註解的接口有多於一個抽象方法的時候會報錯的
  • 「Java」基礎06:編寫入門程序
    仿佛代表著計算機對世界說出來的第一句話,因為它簡潔實用,所以被作為入門程序廣泛使用。Java程序開發三步驟:編寫,編譯,運行一、編寫即開發人員編寫Java原始碼。二、編譯.java文件是開發人員編寫的原始碼,java程序是在JVM上運行的,但是JVM並不認識.java文件。這個時候就必須要將源文件編譯成JVM能看懂的字節碼文件(.class文件)。
  • 最通俗易懂的 Java 10 新特性講解|原力計劃
    你可以像下面這樣使用 var 語法。var hashMap = new HashMap<String, String>();hashMap.put("wechat","wn8398");var string = "hello java 10";var stream = Stream.of(1, 2, 3, 4);
  • 動力節點Java學院2021年Java學習路線圖最新出爐啦
    重點學習:面向對象,集合、IO流、線程、並發、異常及網絡編程等等第二階段:資料庫結合高級框架的學習內容,結合項目,是時候檢驗自己的學習成果,此番課程,含金量非常高,如何你能將這些課程融會貫通,運用自如,那麼你會在現有的知識基礎上更上一層。
  • JAVA零基礎,快速學習(1)
    吶,就有一些想轉行的小夥伴私信我說,寫得太官方了希望能在細分一下。那麼好!我今天就給大家出個基礎快速學習法的系列。下面第一步我先給大家介紹一下JAVA的三大分支,然後依照這樣的目標逐漸完成,相信你一定會成為高手!
  • java中的密碼應用開發快速入門
    今天介紹一下在java中如何進行密碼應用開發。相關密碼學概念及背景知識可參考前面的文章,本文不做過多介紹。示例代碼均來自網上。1.摘要:目前廣泛使用的算法有MD4、MD5、SHA-1,jdk對上面都提供了支持,在java中進行消息摘要很簡單, java.security.MessageDigest提供了一個簡易的操作方法:/***MessageDigestExample.java*Copyright 2005-2-16*/import
  • 一文帶你深扒ClassLoader內核,揭開它的神秘面紗!
    如果覺得 「不錯」的朋友,歡迎 「關注 + 留言 + 分享」,文末有完整的獲取連結,您的支持是我前進的最大的動力!前言ClassLoader 可以說是 Java 最為神秘的功能之一了,好像大家都知道怎麼回事兒 ,又都說不清楚具體是怎麼一回事 。
  • Python和Java語言,新手應該先學哪個
    Python和Java對於編程小白來說,在初入門徑的時候,經常會有一個困惑,拿不定主意,是學習java呢,還是學習python?今天我就給大家說道說道,關於這兩個語言的選擇問題。從這就能看出java這門語言深得人心,是見過世面的程式語言,這麼多年,什麼風雨都經歷過,從網際網路草莽時代,憑藉一己之力,為網際網路推向全宇宙做出了不可磨滅的貢獻,到了移動網際網路時代,Android的興起,讓java又活出了第二個生命,羨煞旁人。再到大數據時代,java又毫無懸念的霸屏了,Hadoop的技術圈裡,java始終是焦點。以上就足以讓你選擇java了。
  • java之字符緩衝輸入流,BufferedReader的簡單介紹
    java之字符緩衝輸出流,BufferedWriter的簡單介紹,這次小編要介紹的是字符緩衝輸入流,具體如下:java.io.BufferedReader extends Reader繼承自父類的共性成員文件:int read()讀取單個字符並返回int read(char[] cbuf)一次讀取多個字符
  • 大數據入門:流處理框架Spark Streaming與Storm
    眾所周知,大數據計算的第一代框架Hadoop,是致力於解決離線計算的問題而產生的,在離線批處理上性能優異,但是在實時流處理上,一直被詬病。Hadoop之後,Spark和Storm在流處理上成為對手。今天的大數據入門分享,我們就主要來講講,流處理框架Spark Streaming與Storm。
  • 會寫Java,不一定會用Collections,你會用嗎
    今天寫一下 Collections,這是Java官方提供的針對集合類的工具類,也是在開發中的一把利刃,能幫我們解決很多開發中的問題,但是依然有很多人不會或者不了解其中的API,一起學習下。1.Collectors 主要是用在java stream 中,是用來最後處理stream的,比如 Collectors.toSet()。2.Collection 是所有集合類的接口類,比如常用的Set,List,Map。
  • java之列印流,printStream的簡單介紹
    各位小夥伴們大家好,在之前的文章中小編介紹了序列化與反序列化的相關知識,這次小編要介紹的是列印流的一些概念還有使用,具體如下:java.io.PrintStream:列印流PrintStream為其他輸出流添加了功能,使它們能夠方便地列印各種數據值和表示形式
  • 程式設計師:Java操作導出excel的三種方法,POI、easyExcel、Hutool
    >調用導出工具類,進行導出(ExportExcel 實體類)ExportExcel erv = new ExportExcel(); // 執行excel操作String fileName = "XXXXXXXXXXXXXXXXXXXXX";// 方法一:
  • 計算機二級java好考嗎?
    今天就來說一下計算二級中的java這一科目。小編通過了19年9月的二級java考試,下面來為大家分享下經驗。要有編程基礎或者編程興趣報考計算機二級java科目的同學,我想應該對java這門語言有一定的了解或者是計算機相關專業的,有一定的編程基礎,或者對編程感興趣,不然也不會報名二級java。
  • 零基礎學java,常見的誤區和解決方法
    寫一篇經驗分享的文章,現在很多人學習java 第一,覺得java很難, 第二,覺得java 找工作不好找, 第三,也有人說java飽和了, 現在確實是行業的要求越來越高了, 早在07年的時候把
  • Java8 中用法優雅的 Stream,性能也「優雅」嗎?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫ava8的Stream API可以極大提高Java程式設計師的生產力,讓程式設計師寫出高效率、乾淨、簡潔的代碼。那麼,Stream API的性能到底如何呢,代碼整潔的背後是否意味著性能的損耗呢?
  • java工程師工資一般多少?java自學容易嗎?公司會要嗎-開課吧
    java自學容易,自學後找到工作也不算難,但是想要摸到這個行業的天花板就很難了!多多交流溝通,其他人自學中走過的路對你而言具有非常寶貴的借鑑異議。還能讓你少走不少彎路!3、找到適合自己的學習方法和教材,書籍和視頻我建議兩者結合,在根據自己的喜好選擇視頻為主還是書本為主,這都是因人而異的,只不過動靜結合學習,既不會太枯燥,也更能有針對性4、擅長利用網上的免費資料,各個網站上Java視頻、資源一搜一大堆,學會分辨品質好壞就是關鍵了,網上還有許多樂於分享的大佬,歡迎大家互相交流學習,千萬別自己悶頭學習