Streams API(一)

stream,也就是java函數式編程,它並不是某種數據結構,它只是數據源的一種視圖。這裏的數據源可以是一個數組,Java容器或I/O channel等。正因如此要得到一個stream通常不會手動創建,而是調用對應的工具方法:

  • 調用Collection.stream()或者Collection.parallelStream()方法
  • 調用Arrays.stream(T[] array)方法
    stream接口繼承關係如圖:
    繼承關係
    你可能會奇怪爲什麼不把IntStream等設計成Stream的子接口?畢竟這接口中的方法名大部分是一樣的。答案是這些方法的名字雖然相同,但是返回類型不同,如果設計成父子接口關係,這些方法將不能共存,因爲Java不允許只有返回類型不同的方法重載。
    雖然大部分情況下stream是容器調用Collection.stream()方法得到的,但stream和collections有以下不同:
  • 無存儲。stream不是一種數據結構,它只是某種數據源的一個視圖,數據源可以是一個數組,Java容器或I/O channel等。
  • 爲函數式編程而生。對stream的任何修改都不會修改背後的數據源,比如對stream執行過濾操作並不會刪除被過濾的元素,而是會產生一個不包含被過濾元素的新stream。
  • 惰式執行。stream上的操作並不會立即執行,只有等到用戶真正需要結果的時候纔會執行。
  • 可消費性。stream只能被“消費”一次,一旦遍歷過就會失效,就像容器的迭代器那樣,想要再次遍歷必須重新生成。
    對stream的操作分爲爲兩類,中間操作(intermediate operations)和結束操作(terminal operations),二者特點是:
  1. 中間操作總是會惰式執行,調用中間操作只會生成一個標記了該操作的新stream,僅此而已。
  2. 束操作會觸發實際計算,計算髮生時會把所有中間操作積攢的操作以pipeline的方式執行,這樣可以減少迭代次數。計算完成之後stream就會失效。
Stream操作分類
中間操作(Intermediate operations) 無狀態(Stateless) unordered()
filter()
map()
mapToInt()
mapToLong()
mapToDouble()
flatMap()
flatMapToInt()
flatMapToLong() flatMapToDouble()
peek()
有狀態(Stateful) distinct()
sorted()
sorted()
limit()
skip()
結束操作(Terminal operations) 非短路操作 forEach()
forEachOrdered()
toArray()
reduce()
collect()
max()
min()
count()
短路操作(short-circuiting) anyMatch()
allMatch()
noneMatch()
findFirst()
findAny()

區分中間操作和結束操作最簡單的方法,就是看方法的返回值,返回值爲stream的大都是中間操作,否則是結束操作。

stream方法使用

stream跟函數接口關係非常緊密,沒有函數接口stream就無法工作。回顧一下:函數接口是指內部只有一個抽象方法的接口。通常函數接口出現的地方都可以使用Lambda表達式,所以不必記憶函數接口的名字。
forEach()
我們對forEach()方法並不陌生,在Collection中我們已經見過。方法簽名爲void forEach(Consumer<? super E> action),作用是對容器中的每個元素執行action指定的動作,也就是對元素進行遍歷。

// 使用Stream.forEach()迭代                                                                  
Stream<String> stream = Stream.of("I", "love", "you", "too");
stream.forEach(str -> System.out.println(str));

filter()
函數原型爲Stream filter(Predicate<? super T> predicate),作用是返回一個只包含滿足predicate條件元素的Stream。

// 保留長度等於3的字符串                       
Stream<String> stream= Stream.of("I", "love", "you", "too");
stream.filter(str -> str.length()==3)
    .forEach(str -> System.out.println(str));

distinct()
函數原型爲Stream distinct(),作用是返回一個去除重複元素之後的Stream。

Stream<String> stream= Stream.of("I", "love", "you", "too", "too");
stream.distinct()
    .forEach(str -> System.out.println(str));

sorted()
排序函數有兩個,一個是用自然順序排序,一個是使用自定義比較器排序,函數原型分別爲Stream sorted()和Stream

sorted(Comparator<? super T> comparator)。
Stream<String> stream= Stream.of("I", "love", "you", "too");
stream.sorted((str1, str2) -> str1.length()-str2.length())
    .forEach(str -> System.out.println(str));

map()
函數原型爲 Stream map(Function<? super T,? extends R> mapper),作用是返回一個對當前所有元素執行執行mapper之後的結果組成的Stream。直觀的說,就是對每個元素按照某種操作進行轉換,轉換前後Stream中元素的個數不會改變,但元素的類型取決於轉換之後的類型。

Stream<String> stream = Stream.of("I", "love", "you", "too");
stream.map(str -> str.toUpperCase())
    .forEach(str -> System.out.println(str));

flatMap()
函數原型爲 Stream flatMap(Function<? super T,? extends Stream<? extends R>> mapper),作用是對每個元素執行mapper指定的操作,並用所有mapper返回的Stream中的元素組成一個新的Stream作爲最終返回結果。說起來太拗口,通俗的講flatMap()的作用就相當於把原stream中的所有元素都"攤平"之後組成的Stream,轉換前後元素的個數和類型都可能會改變。

Stream<List<Integer>> stream = Stream.of(Arrays.asList(1,2), Arrays.asList(3, 4, 5));
stream.flatMap(list -> list.stream())
    .forEach(i -> System.out.println(i));

轉自:https://github.com/CarpenterLee/JavaLambdaInternals/blob/master/4-Streams%20API(I).md?spm=ata.13261165.0.0.1a35359f8hp4ix&file=4-Streams%20API(I).md#stream%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8

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