【JDK 8特性】Stream API 詳解

樂猿社區,程序員的花果山java

Stream 做爲 Java 8 的一大亮點,它與 java.io 包裏的 InputStream 和 OutputStream 是徹底不一樣的概念。Java 8 中的 Stream 是對集合(Collection)對象功能的加強,它專一於對集合對象進行各類很是便利、高效的聚合操做(aggregate operation),或者大批量數據操做 (bulk data operation)。Stream API 藉助於 Lambda 表達式,極大的提升編程效率和程序可讀性。程序員

什麼是 Stream?

Stream 就如同一個迭代器(Iterator),單向,不可往復,數據只能遍歷一次,遍歷過一次後即用盡了,就比如流水從面前流過,一去不復返。而和迭代器又不一樣的是,Stream 能夠並行化操做,迭代器只能命令式地、串行化操做。顧名思義,當使用串行方式去遍歷時,每一個 item 讀完後再讀下一個 item。而使用並行去遍歷時,數據會被分紅多個段,其中每個都在不一樣的線程中處理,而後將結果一塊兒輸出。編程

流的操做類型分爲兩種:

  • Intermediate:一個流能夠後面跟隨零個或多個 intermediate 操做。其目的主要是打開流,作出某種程度的數據映射/過濾,而後返回一個新的流,交給下一個操做使用。這類操做都是惰性化的(lazy),就是說,僅僅調用到這類方法,並無真正開始流的遍歷。
操做 類型 返回類型 目的
filter 中間操做 Stream<T> 過濾元素
distinct 中間操做 Stream<T> 去掉重複的元素
skip 中間操做 Stream<T> 跳過指定數量的元素
limit 中間操做 Stream<T> 限制元素的數量
map 中間操做 Stream<T> 流的轉化
flatmap 中間操做 Stream<T> 流的扁平化
sorted 中間操做 Stream<T> 元素排序

map與flatmap的區別:map是將list轉成list,而flatmap是將多個List合併成一個list併發

  • Terminal:一個流只能有一個 terminal 操做,當這個操做執行後,流就被使用「光」了,沒法再被操做。因此這一定是流的最後一個操做。Terminal 操做的執行,纔會真正開始流的遍歷,而且會生成一個結果,或者一個 side effect。
操做 類型 返回類型 目的
forEach 終端操做 void 消費流中的每一個元素,返回void
count 終端操做 R 返回流中元素的個數,返回long
collect 終端操做 Stream<T> 把流歸約爲一個集合
anyMatch 終端操做 boolean 流中是否有符合要求的元素
noneMatch 終端操做 boolean 流中是否沒有任何符合要求的元素
allMatch 終端操做 boolean 流中是否全部元素都是符合要求的
findAny 終端操做 Optional<T> 查找符合要求的元素
findFirst 終端操做 Optional<T> 查找第一個符合要求的元素
reduce 終端操做 Optional<T> 歸約

怎樣建立流?

Stream 提供兩咱建立流的方式dom

  • stream() − 爲集合建立串行流。
  • parallelStream() − 爲集合建立並行流。

Stream提供串行和並行兩種模式進行匯聚操做,併發模式可以充分利用多核處理器的優點,使用 fork/join 並行方式來拆分任務和加速處理過程。stream 是一個函數式語言+多核時代綜合影響的產物編程語言

過濾元素 - filter

如下的代碼返回不爲空的字符串ide

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取不爲空的字符串
List<String>  result = strings.stream().filter(string -> string.isEmpty()).collect(Collectors.toList());

篩選重複的元素 - distinct

如下代碼會篩選出列表中全部的偶數,並確保沒有 重複函數

List<Integer> numbers = Arrays.asList(1,2,1,3,3,2,4);
 //去重元素2
numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);

跳過指定數量的元素 - skip

返回一個扔掉了前n個元素的流。若是流中元素不足n個,則返回一 個空流。limit(n) 和 skip(n) 是互補的。線程

//去掉符合要求的集合中的前2個元素後返回
List<User> dishSkip = userList.stream()
        .filter(d -> d.getAge() > 20).skip(2).collect(Collectors.toList());

限制元素數量 - limit

返回一個不超過給定長度的流。所需的長度做爲參數傳遞 給limit。若是流是有序的,則最多會返回前n個元素。code

//只返回符合要求的前3個元素
List<User> dishLimits = userList.stream().filter(d -> d.getAge() > 30).limit(3).collect(Collectors.toList());

map 操做

接受一個函數做爲參數。這個函數會被應用到每一個元素上,並將其映 射成一個新的元素

//轉爲字符串長度的集合
List<String> words = Arrays.asList("Hello", "World");
List<Integer> wordLens = words.stream().map(String::length).collect(Collectors.toList());

flatmap 操做

flatmap 方法讓你把一個流中的每一個值都換成另外一個流,而後把全部的流鏈接起來成爲一個流。

//使用flatMap找出單詞列表中各不相同的字符
List<String> words = Arrays.asList("Hello", "World");
List<String> wordMap = words.stream()
      .map(word -> word.split(""))
      .flatMap(Arrays::stream).distinct().collect(Collectors.toList());

排序 - sorted

sorted 方法用於對流進行排序。如下代碼片斷使用 sorted 方法對輸出的 10 個隨機數進行排序:

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

Collectors 聚合操做

Collectors 類實現了不少歸約操做,例如將流轉換成集合和聚合元素。Collectors 可用於返回列表或字符串:

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("篩選列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合併字符串: " + mergedString);

查找和匹配

查找和匹配操做包含anyMatch,allMatch,noneMatch,findFirst,findAny,通常狀況下使用的少

reduce歸約操做

reduce操做是如何做用於一個流的:Lambda反覆結合每一個元素,直到流被歸約成一個值。reduce方法接受兩個參數:一個初始值,這裏是0;一個 BinaryOperator<T> 來將兩個元素結合起來產生一個新值, 這裏咱們用的是 lambda (a, b) -> a + b 歸約操做包含sum(元素求和)、min(最小值)、max(最大值)、count(求總數)

總結

  • Stream每一個操做都是依賴Lambda表達式或方法引用。
  • Stream操做是一種聲明式的數據處理方式。
  • Stream操做提升了數據處理效率、開發效率。

鼓勵把新的Java8特性引入到目前的項目中,一個長期配合的團隊以及一門古老的編程語言都須要不斷的注入新活力,不然不進則退

[]

相關文章
相關標籤/搜索