一文帶你入門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 流實在是太強大了?原創不易,莫要白票,請你為本文點讚個吧,這將是我寫作更多優質文章的最強動力。

相關焦點

  • java如何快速入門?
    java如何快速入門正確掌握Java的基本知識由於Java為開發人員提供了如此多的特性和選項,人們有時會被分散注意力在太短的時間內學習了太多的東西java如何快速入門真正弄懂你敲出的代碼是做什麼的只要你理解了代碼背後的思想,算法和整個編譯過程就會顯得非常有意義。
  • 巧用Java8中的Stream,讓集合操作飛起來!
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫作者:堅持就是勝利juejin.im/post/5d5e2616f265da03b638b28a簡介
  • Java中Lambda表達式的5種不同語法
    在這種情況下,它是一個單一表達式-Integer.compare(m.length(), n.length())Output:[a, is, java, site, creek, program]2.可以推斷參數類型如果可以從上下文中推斷出參數的參數類型,則可以省略該類型。
  • 動力節點Java學院2021年Java學習路線圖最新出爐啦
    重點學習:面向對象,集合、IO流、線程、並發、異常及網絡編程等等第二階段:資料庫結合高級框架的學習內容,結合項目,是時候檢驗自己的學習成果,此番課程,含金量非常高,如何你能將這些課程融會貫通,運用自如,那麼你會在現有的知識基礎上更上一層。
  • 散文翻譯 《溪水》The Stream 翻譯
    the stream; the indigo water surface was suffused with a rainbow of colors.    水是怎樣的開心呵,她將那可憐的失路的小紅葉兒,推推擠擠的推到一個漩渦裡,使他滴滴溜溜的打圓轉兒;那葉向前不得,向後不能,急得幾乎哭出來;水笑嘻嘻的將手一松,他才一溜煙的逃走了。
  • JAVA基礎之Applet
    Java的入門比我想像中的還要簡單的多,目前為止我已經對Java的基本語法結構有所了解。但我知道,深入的研究任何一門語言,都需要時間和實踐的積累.Applet是Java編寫的可以在瀏覽器端運行的代碼,它與應用程式的明顯區別在於其執行方式的不同,應用程式如C程序是從main()主程序開始運行的,而Applet則比較複雜.具體如何複雜我不太清楚,但我會慢慢清楚的。
  • 零基礎學習Java者必須了解的Java語言常識以及知識
    那麼你是否想要學習Java語言了,畢竟TIOBE的排名代表著程序語言的未來趨勢。針對零基礎的初學者,入門Java語言你就必須了解一些常識知識。Java簡介Java是由Sun Microsystems公司於1995年5月推出的Java面向對象程序設計語言和Java平臺的總稱。由James Gosling和同事們共同研發,並在1995年正式推出。
  • java之列印流,printStream的簡單介紹
    各位小夥伴們大家好,在之前的文章中小編介紹了序列化與反序列化的相關知識,這次小編要介紹的是列印流的一些概念還有使用,具體如下:java.io.PrintStream:列印流PrintStream為其他輸出流添加了功能,使它們能夠方便地列印各種數據值和表示形式
  • 跟光磊學Java開發-Java並發編程入門
    創建線程的兩種方式   在Java中java.lang.Thread類表示線程。如果想要創建線程就需要創建Thread類的對象  繼承Thread類,重寫run()方法  PrintThread繼承了java.lang.Thread,並且重寫任務的方法@Log4j2註解主要用於日誌記錄,通過由於log42.xml文件中配置了控制臺輸出的日誌會列印線程信息,因此在程序運行時可以看到當前運行的線程名稱。
  • 萬字梳理,帶你拿下 Java 面試題!
    因為都是字符串啊,字符串比較的不都是堆空間嗎,猛然一看發現好像永遠也不會走,但是你忘記了 String.intern() 方法,它表示的概念在不同的 JDK 版本有不同的區分。在 JDK1.7 及以後調用 intern 方法是判斷運行時常量池中是否有指定的字符串,如果沒有的話,就把字符串添加到常量池中,並返回常量池中的對象。
  • Java零基礎手把手系列:HashMap排序方法一網打盡
    HashMap的排序在一開始學習Java的時候,比較容易暈,今天總結了一些常見的方法,一網打盡。HashMap的排序入門,看這篇文章就夠了。1.使用ArrayList我們也可以使用ArrayList來輔助排序,和前文不一樣的是:這裡ArrayList只能按照Key或者Value排序3.1 Sort by Key使用ArrayList來輔助進行Key的排序:只需要從Map中獲取到Key的集合,構造List即可,然後使用Collections
  • 你必須掌握的 21 個 Java 核心技術!
    這個知識點是最最基本的java開發者需要掌握的,第一個肯定是教你如何在命令行中執行java程序,但是很多人一旦把java學完了,IDE用上了,就把這個都忘了。為什麼強調要知道這個呢,知道了java最純粹的啟動方式之後,你才能在啟動出問題的時候,去分析當時啟動的目錄多少,執行命名如何,參數如何,是否有缺失等。這樣有利於你真正開發中去解決那些奇奇怪怪的可能和環境相關的問題。
  • 編程入門先學什麼?零經驗的人學編程難嗎
    不少朋友在學習編程時只簡單地學習語法、結構,枯燥而且目的性也不強,會大大降低初學者的興趣和學習效果。而一般的書籍,也只從語言本身去講解語法和舉一些針對這些語法的應用例子,跟使用說明書沒有太大差別,沒有起到灌輸編程思想,培養編程感覺的作用。
  • Java經典面試題Spring是什麼 Spring框架入門詳解
    這是初級開發人員必然被問道的問題,如果你不懂Spring你就無法從事這一行業,此處僅限技術人員,公司的繼承人等其他個例不受此限制。那麼Spring是什麼呢,Spring遵循分層的結構思想什麼什麼實現了高內聚低耦合巴拉巴拉一大堆,咬文嚼字不是我的強項,直接開幹,讓你們看看Spring到底是什麼東西。
  • 好程式設計師Java培訓分享Java讀寫Properties配置文件
    2.Properties中的主要方法 (1)load(InputStream inStream) 這個方法可以從.properties屬性文件對應的文件輸入流中
  • 擴展Hibernate以處理Java流查詢
    流處理現在,我們將引導您完成在資料庫應用程式中設置JPAstreamer的簡單過程。為此,您的應用程式必須使用Java 8(或更高版本)和Hibernate或負責對象持久性的其他JPA提供程序(如果您希望在不使用JPA的情況下使用Stream API,最好使用開源的Stream ORM Speedment)。
  • 使用Java8 Stream API對Map類型按照鍵或值進行排序
    一、什麼是Java 8 Stream使用Java 8 Streams,我們可以按鍵和按值對映射進行排序。這個函數有三個參數:參數一:向map裡面put的鍵參數二:向map裡面put的值參數三:如果鍵發生重複,如何處理值。可以是一個函數,也可以寫成lambda表達式。
  • Effective java 中文版 PDF
    這本《Effective java》是必不可少的一本,豆瓣評分高達9.8分,文末有獲取方式。《Effective Java》第三版一共包含了 90 條極具實用價值的經驗規則,每條規則都值得 Java 程式設計師在實戰中去參照。
  • 面試官:連Serializable都不知道是什麼,你這5年都幹些什麼了?
    文|洪生鵬程式設計師面試時,序列化知識點經常會遇到。張工是一名java程式設計師,工作5年了,一直從事java開發。最近到某網際網路公司面試,做了筆試題後,有一道筆試題是這樣子的:Serializable有什麼作用,張工沒有作答,面談時面試官又問了,張工回答不出個所以然。