1. 程式人生 > >JAVA 8 Streams 1

JAVA 8 Streams 1

Java 8中的Stream其實是函數語言程式設計裡Monad的概念,關於Monad,可以參考這篇文章。Monad就是一種設計模式,表示將一個運算過程,通過函式拆解成互相連線的多個步驟,有點鏈式操作的感覺。先看一個例子:

import java.util.Arrays;
import java.util.List;

public class Snippet{
    public static void main(String[] args){
        List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");

        myList
            .stream()
            .filter(s -> s.startsWith("c"))       //過濾以c字母開頭
            .map(String::toUpperCase)        //字元變成大寫
            .sorted()                                     //排序
            .forEach(System.out::println);    //列印輸出
    }
}

       Stream 不是集合元素,它不是資料結構並不儲存資料,它是有關演算法和計算的,它更像一個高階版本的 Iterator。原始版本的 Iterator,使用者只能顯式地一個一個遍歷元素並對其執行某些操作;高階版本的 Stream,使用者只要給出需要對其包含的元素執行什麼操作,比如 “過濾掉長度大於 10 的字串”等,Stream 會隱式地在內部進行遍歷,做出相應的資料轉換。

       Stream 就如同一個迭代器(Iterator),單向,不可往復,資料只能遍歷一次,遍歷過一次後即用盡了,就好比流水從面前流過,一去不復返。

       而和迭代器又不同的是,Stream 可以並行化操作,迭代器只能命令式地、序列化操作。顧名思義,當使用序列方式去遍歷時,每個 item 讀完後再讀下一個 item。而使用並行去遍歷時,資料會被分成多個段,其中每一個都在不同的執行緒中處理,然後將結果一起輸出。Stream 的並行操作依賴於 Java7 中引入的 Fork/Join 框架(JSR166y)來拆分任務和加速處理過程。Java 的並行 API 演變歷程基本如下:

  • 1.0-1.4 中的 java.lang.Thread
  • 5.0 中的 java.util.concurrent
  • 6.0 中的 Phasers 等
  • 7.0 中的 Fork/Join 框架
  • 8.0 中的 Lambda

當我們使用一個流的時候,通常包括三個基本步驟:

獲取一個數據源(source)→ 資料轉換→執行操作獲取想要的結果,每次轉換原有 Stream 物件不改變,返回一個新的 Stream 物件(可以有多次轉換),這就允許對其操作可以像鏈條一樣排列,變成一個管道,如下圖所示。

1)使用Stream的好處

  • 對JAVA集合(Collection)物件功能的增強,方便對集合進行各類操作(過濾、求最大值、最小值、統計等);
  • 更加高效,提供序列和並行兩種模式,並行模式利用了Java中的fork/join框架技術,能充分利用多核處理器,提高程式併發性;

2)Stream的特徵

  • 不是一個數據結構,為lambda表示式設計(所有 Stream 的操作必須以 lambda 表示式為引數)。它沒有內部儲存,它只是用操作管道從 source(資料結構、陣列、generator function、IO channel)抓取資料。它也絕不修改自己所封裝的底層資料結構的資料。例如 Stream 的 filter 操作會產生一個不包含被過濾元素的新 Stream,而不是從 source 刪除那些元素。
  • 不支援索引訪問
  • 很方便的作為陣列或集合輸出
  • 支援惰性訪問(Intermediate都是惰性的)
  • 平行計算
  • 資料來源本身可以是無限的(集合有固定大小,Stream 則不必。limit(n) 和 findFirst() 這類的 short-circuiting 操作可以對無限的 Stream 進行運算並很快完成)

3)Stream的操作型別:
Stream有兩種型別的操作:Intermediate操作和Terminal操作。類似於spark中RDD的transform和action兩種操作。

  • Intermediate(中間操作):Stream可以進行多次的Intermediate操作,如前面開頭的那個例子,其中filter、map、sorted都是Intermediate操作,注意該操作是惰性化的,當呼叫到該方法的時候,並沒有真正開始Stream的遍歷。
  • Terminal(結束操作):一個Stream只有一個Terminal操作,如前面開頭的那個例子,其中forEach就是Terminal操作,Terminal操作是Stream的最後一個操作,這時候才會開始Stream的遍歷。

4)惰性化:

在對於一個 Stream 進行多次轉換操作 (Intermediate 操作),每次都對 Stream 的每個元素進行轉換,而且是執行多次,這樣時間複雜度就是 N(轉換次數)個 for 迴圈裡把所有操作都做掉的總和嗎?其實不是這樣的,轉換操作都是 lazy 的,多個轉換操作只會在 Terminal 操作的時候融合起來,一次迴圈完成。我們可以這樣簡單的理解,Stream 裡有個操作函式的集合,每次轉換操作就是把轉換函式放入這個集合中,在 Terminal 操作的時候迴圈 Stream 對應的集合,然後對每個元素執行所有的函式。

5)短路(short-circuiting):

       有些操作不需要處理整個流就能得到結果。例如,假設你需要對一個用 and 連起來的大布爾表示式求值。不管表示式有多長,你只需找到一個表示式為 false ,就可以推斷整個表示式將返回 false ,所以用不著計算整個表示式。這就是短路。對於流而言,某些操作(例如 allMatch 、 anyMatch 、 noneMatch 、 findFirst 和 findAny )不用處理整個流就能得到結果。只要找到一個元素,就可以有結果了。同樣, limit 也是一個短路操作:它只需要建立一個給定大小的流,而用不著處理流中所有的元素。在碰到無限大小的流的時候,這種操作就有用了:它們可以把無限流變成有限流。

  • 對於一個 intermediate 操作,如果它接受的是一個無限大(infinite/unbounded)的 Stream,但返回一個有限的新 Stream。
  • 對於一個 terminal 操作,如果它接受的是一個無限大的 Stream,但能在有限的時間計算出結果。

當操作一個無限大的 Stream,而又希望在有限時間內完成操作,則在管道內擁有一個 short-circuiting 操作是必要非充分條件。

1、java.util.stream包結構

1)BaseStream介面:

所有Stream介面型別的父介面,它繼承自AutoClosable介面,定義了一些所有Stream都具備的行為。因為繼承自AutoClosable介面,所以所有的Stream型別都可以用在Java 7中引入的try-with-resource機制中,以達到自動關閉資源的目的。實際上,只有當Stream是通過Socket,Files IO等方式建立的時候,才需要關閉它。對於來自於Collections,Arrays的Stream,是不需要關閉的。

2)Stream介面:

定義了眾多Stream應該具有的行為。最典型的比如filter方法族,map方法族以及reduce方法族,這三個方法是FunctionalProgramming的標誌。典型的Map-Filter-Reduce模式便是依靠這三個操作來定義的。

與此同時,Stream介面還定義了一些用於建立Stream的static方法,建立的Stream可以是有限的,也可以是無限的。有限的很好理解,而無限Stream是一個新概念,通過generate方法或者iterate方法實現。

3)IntStream, LongStream 以及 DoubleStream 介面:

基於原生型別int, long以及double的Stream。提供了眾多型別相關的操作。典型的例如,sum方法,min/max方法,average方法等。這些方法都是Reduce操作的具體實現。

4)Collect介面:

對於Reduce操作的抽象。此介面中定義了常用的Reduce操作。其中定義的Reduce操作可以通過序列或者並行的方式進行實現。BaseStream介面中的parallel,sequential,unordered方法提供的高層API使併發程式設計變得非常簡潔。畢竟,Map-Filter-Reduce模式的靈魂就在於平行計算。

5)Collectors類:

提供了眾多可以直接使用的Reduce操作。典型的比如groupingBy以及partitioningBy操作。它們都可以通過序列或者並行的方式進行實現。比如,groupingByConcurrent會使用並行的方式進行grouping操作。

6)StreamSupport類:

提供了底層的一些用於操作Stream的方法,如果不需要建立自己的Stream,一般不需要使用它。

2、建立Stream物件

1)從 Collection 和陣列:

  • Collection.stream()
  • Collection.parallelStream()
  • Arrays.stream(T array) or Stream.of()

2)從 BufferedReader

  • java.io.BufferedReader.lines()

3)靜態工廠

  • java.util.stream.IntStream.range()
  • java.nio.file.Files.walk()

4)自己建立

  • java.util.Spliterator

5)其它

  • Random.ints()
  • BitSet.stream()
  • Pattern.splitAsStream(java.lang.CharSequence)
  • JarFile.stream()

。。。

參考:

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

相關推薦

JAVA 8 Streams 1

Java 8中的Stream其實是函數語言程式設計裡Monad的概念,關於Monad,可以參考這篇文章。Monad就是一種設計模式,表示將一個運算過程,通過函式拆解成互相連線的多個步驟,有點鏈式操作的感覺。先看一個例子: import java.util.Arrays; i

Java 8 Streams常用API簡介

常用的幾個API:filter、map、forEach、sorted、findFirst、reduce、limit/skip、min/max/distinct、allMatch/anyMatch/noneMatch map:把input Stream的每一個元素,對映成output Stre

Java 8 Streams 中的資料庫 CRUD 操作

接觸一個新工具的時候,剛開始要克服的最大障礙就是如何讓你自己先嚐試做出一個小東西來。現在你也許對 Java 8 中 新的 Stream API 的運作方式在理解上比較自信,但你也許並沒用它來進行過資料庫查詢操作。為了幫助你開始使用 Stream API 來對 SQL 資料

Java 8 Streams API 詳解

流式程式設計作為Java 8的亮點之一,是繼Java 5之後對集合的再一次升級,可以說Java 8幾大特性中,Streams API 是作為Java 函式式的主角來設計的,誇張的說,有了Streams API之後,萬物皆可一行程式碼。 什麼是Stream Stream被翻譯為流,它的工作過程像將一瓶水匯入有很

Java 8 新特性1-函數式接口

實例 his sys subject 生成 license object類 acc class類 Java 8 新特性1-函數式接口 (原) Lambda表達式基本結構: (param1,param2,param3) -> {代碼塊} 例1: package

2017面向對象程序設計(Java) 第1周學習指導及要求(2017.8.24-2017.8.27)

令行 str applet 面向 學習目標 對象 com 變量 課程學習 2017面向對象程序設計(Java) 第1周學習指導及要求(2017.8.24-2017.8.27) 學習目標 了解課程上課方式及老師教學要求,掌握課程學習必要的軟件工具; 簡單了解Java特點

Java 8新特性之接口改善(八惡人-1

1.8 我想 when 直接 有一個 圖片 class java類 聖誕節 Daisy Donergue 多莫歌·黛西 “By woman, you mean her?” 她也能叫女人?   Java 8在13年9月發布,寫這篇博文的時間已經是17年12月份了。

Java 8 集合之流式(Streams)操作, Streams API 詳解

因為當時公司的業務需要對集合進行各種各樣的業務邏輯操作,為了提高效能,就用到了這個東西,因為以往我們以前用集合都是需要去遍歷(序列),所以效率和效能都不是特別的好,而Streams就可以使用並行的方式來操作集合。 Stream 就如同一個迭代器(Iterator),單向,不可往復,資料只能遍歷一次,遍歷過一

1java 8 流的學習----篩選和切片

篩選、切片和匹配  查詢、匹配和歸約  使用數值範圍等數值流  從多個源建立流  無限流 /** * 篩選和切片 */ public class Demo01 { public static void main(String[] args) { List&l

Java 8 中的 新特性Streams

Stream 作為 Java 8 的一大亮點,它與 java.io 包裡的 InputStream 和 OutputStream 是完全不同的概念。 使用 Stream API 無需編寫一行多執行緒的程式碼,就可以很方便地寫出高效能的併發程式。所以說,Java 8 中首次出現的 java.util.

Streams filter 例子 (函數語言程式設計 ) Java 8

在本教程中,我們將向你展示一些java 8個例子來演示的流filter(),collect()使用,findany()和orelse(). 1. Streams filter() and collect()   1.1 Java 8之前, 過濾一 List 

[轉]Java 8 中的 Streams API 詳解

原文連結:https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/   為什麼需要 Stream Stream 作為 Java 8 的一大亮點,它與 java.io 包裡的 InputStream 和 OutputStrea

JAVA 8 併發增強(1) 多執行緒修改某個計數器的方式

Q:如何正確的併發修改一個AtomicLong的值? /* 不同執行緒檢測最大值 */ AtomicLong largest = new AtomicLong(); long obsvValue = 0; /* 錯誤的方式,此更新不是原子性的 */ largest.

Java 8 中的 Streams API 詳解

Streams 的背景,以及 Java 8 中的使用詳解 陳 爭雲, 佔 宇劍, 和 司 磊 2014 年 9 月 11 日釋出 49 為什麼需要 Stream Stream 作為 Java 8 的一大亮點,它與 java.io 包裡的 InputStre

Java 8 學習筆記1——Java 8 概述

Java 8提供了一個新的API(稱為“流”,Stream),它支援許多處理資料的並行操作,其思路和在資料庫查詢語言中的思路類似——用更高階的方式表達想要的東西,而由“實現”(在這裡是Streams庫)來選擇最佳低階執行機制。這樣就可以避免用synchronized編寫程式碼,這一程式碼不僅

Java 8: Lambdas, Part 1

原文連結  作者:Ted Neward  譯者:趙峰 瞭解Java8 中的lambda表示式 對開發人員來說沒有什麼比自己選擇的語言或平臺釋出新版本更令人激動了。Java開發者也不例外。實際上,我們更期待新版本的釋出,有一部分原因是因為在不久前我們還在考慮Java的前途,因為Java的創造者—

Java特種兵》1.8 老A是在逆境中迎難而上者

本文是《Java特種兵》的樣章,感謝博文視點和作者授權本站釋出 1.8 老A是在逆境中迎難而上者 小胖哥雖然不是一個“傳道者”,但是喜歡小小論道,因為在人生的道路上,很多時候你我都會面臨許多糾結的事情,而這個時候我們的態度會決定命運,而道就是道理和方法。 ◎ 作為“程式設計師”,每天被要求修

Java/JDK 8 新特性1.8對於1.7做了哪些優化/改進

Java 8 新特性 Java 8 (又稱為 jdk 1.8) 是 Java 語言開發的一個主要版本。 Oracle 公司於 2014 年 3 月 18 日釋出 Java 8 ,它支援函數語言程式設計,新的 JavaScript 引擎,新的日期 API,新的Str

FastQuery 1.0.20 釋出,Java 8 簡易資料持久層

FastQuery 1.0.20 釋出了,更新如下: 主要增強SQL in: "?"索引方式 @Query("select * from UserInfo where name in (?1)") List<UserInfo> findByNameIn(S

Java 8 Lambda(類庫篇——Streams API,Collector和並行)

參考資料:1、背景自從lambda表示式成為Java語言的一部分之後,Java集合(Collections)API就面臨著大幅變化。為了不推到重來,所以對現有的API進行改進。為現有的介面(例如Collection,List和Stream)增加擴充套件方法;在類庫中增加新的流