Java8 的這個特性,用起來真的很爽

一直在寫中間件相關的代碼,提供SDK給業務方使用,但很多業務方還一直停留在1.7版本,遲遲不升級,爲了兼容性,不敢在代碼中使用Java8的一些新特性,比如Stream之類的,雖然不能用,但還是要學一下。

Stream 是什麼

Stream 是Java 8中添加的一個新特性,它與 java.io 包裏的 InputStream 和 OutputStream 是完全不同的概念。它藉助於 Lambda 表達式,可以讓你以一種聲明的方式處理數據,可以極大提高Java程序員的生產力,讓程序員寫出高效率、乾淨、簡潔的代碼。

Stream Demo

直接上Demo,感受一下

List<String> myList = Arrays.asList("a", "b", "c", "d", "e");myList.stream()    .filter(s -> s.startsWith("1"))    .map(String::toUpperCase)    .sorted()    .forEach(System.out::println);

Stream 如何工作

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

  • 獲取一個數據源(source)

  • 數據轉換

  • 執行操作獲取想要的結果

每次轉換原有 Stream 對象不改變,返回一個新的 Stream 對象(可以有多次轉換),這就允許對其操作可以像鏈條一樣排列,變成一個管道,如下圖所示。

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1

在Stream中,分爲兩種操作

  • 中間操作

  • 結束操作

中間操作返回Stream,終端操作返回void或者非Stream結果,在demo中, filtermapsorted都算是中間操作,而 forEach是一個結束操作。

Stream 如何生成

創建Stream的方式很多,最常見的是從Collections,List 和 Set中生成

List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");Stream<String> stream  = myList.stream()

在對象myList上調用方法 stream() 返回一個常規對象Stream。

也可以從一堆已知對象中生成。

Stream<String> stream  = Stream.of("a1", "a2", "a3")

當然了,還有其它方式:

  • Collection.stream()

  • Collection.parallelStream()

  • BufferedReader.lines()

  • Files.walk()

  • BitSet.stream()

  • Random.ints()

  • JarFile.stream()

  • ....

常規操作

forEach

forEach方法接收一個 Lambda 表達式,用來迭代流中的每個數據

Stream.of(1, 2, 3).forEach(System.out::println);// 1// 2// 3

map

map 用於映射每個元素到對應的結果

Stream.of(1, 2, 3).map( i -> i*i).forEach(System.out::println);// 1// 4// 9

filter

filter 用於通過設置的條件過濾出元素

Stream.of(1, 2, 3).filter( i -> i == 1).forEach(System.out::println);// 1

limit

limit 用於用於獲取指定數量的流

Stream.of(1, 2, 3, 4, 5).limit(2).forEach(System.out::println);// 1// 2

sorted

sorted 用於對流進行排序

Stream.of(4, 1, 5).sorted().forEach(System.out::println);// 1// 4// 5

Match

有三個 match 方法,從語義上說:

  • allMatch:Stream 中全部元素符合傳入的 predicate,返回 true

  • anyMatch:Stream 中只要有一個元素符合傳入的 predicate,返回 true

  • noneMatch:Stream 中沒有一個元素符合傳入的 predicate,返回 true

它們都不是要遍歷全部元素才能返回結果。例如 allMatch 只要一個元素不滿足條件,就 skip 剩下的所有元素,返回 false。

boolean result = Stream.of("a1", "a2", "a3").allMatch(i -> i.startsWith("a"));System.out.println(result);// true

reduce

reduce 方法根據指定的函數將元素序列累積到某個值。此方法有兩個參數:

  • 起始值

  • 累加器函數。

如果有一個List,希望得到所有這些元素和一些初始值的總和。

int result = Stream.of(1, 2, 3).reduce(20, (a,b) -> a + b);System.out.println(result);// 26

collect

Collectors類中提供了功能豐富的工具方法

  • toList

  • toSet

  • toCollection

  • toMap

  • ...

而這些方法,都需要通過 collect 方法傳入。

Set<Integer> result = Stream.of(1, 1, 2, 3).collect(Collectors.toSet());System.out.println(result);// [1, 2, 3]

collect 可以把Stream數據流轉化爲Collection對象,

騷技巧

for循環

除了常規的對象Stream,還有一些有特殊類型的Stream,用於處理基本數據類型int、long和double,它是IntStream、LongStream和DoubleStream。

比如可以使用IntStream.range()來代替常規的for循環。

IntStream.range(1, 4).forEach(System.out::println);

隨機數

Random的ints方法可以返回一個隨機數據流,比如返回1到100的10個隨機數。

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

大小寫轉化

List<String> output = wordList.stream()  .map(String::toUpperCase)  .collect(Collectors.toList());

Stream 特點

總之,Stream 的特性可以歸納爲:

無存儲

Stream並不是一種數據結構,它只是某種數據源的一個視圖

安全性

對Stream的任何修改都不會修改背後的數據源,比如對stream執行過濾操作並不會刪除被過濾的元素,而是會產生一個不包含被過濾元素的新Stream。

惰式執行

Stream上的操作並不會立即執行,只有等到用戶真正需要結果的時候纔會執行。

一次性

Stream只能被“消費”一次,一旦遍歷過就會失效,就像容器的迭代器那樣,想要再次遍歷必須重新生成。

lambda

所有 Stream 的操作必須以 lambda 表達式爲參數


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章