java8 Stream api小記

學着使用stream api,並作一些總結java

很好的中文文檔  https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/api

 

流的構成

當咱們使用一個流的時候,一般包括三個基本步驟:數組

獲取一個數據源(source)→ 數據轉換→執行操做獲取想要的結果,每次轉換原有 Stream 對象不改變,返回一個新的 Stream 對象(能夠有屢次轉換),這就容許對其操做能夠像鏈條同樣排列,變成一個管道。數據結構

常見用法多線程

  • Collection.stream()
  • Collection.parallelStream() //並行流,不須要再寫多線程代碼,全部對它的操做會自動並行進行的
  • Arrays.stream(T array) or Stream.of()

流的操做類型分爲兩種:less

  • Intermediate:一個流能夠後面跟隨零個或多個 intermediate 操做。其目的主要是打開流,作出某種程度的數據映射/過濾,而後返回一個新的流,交給下一個操做使用。這類操做都是惰性化的(lazy),就是說,僅僅調用到這類方法,並無真正開始流的遍歷。如: map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
  • Terminal:一個流只能有一個 terminal 操做,當這個操做執行後,流就被使用「光」了,沒法再被操做。因此這一定是流的最後一個操做。Terminal 操做的執行,纔會真正開始流的遍歷,而且會生成一個結果,或者一個 side effect。如: forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

 

流的使用詳解

常見案例ide

一個很簡單的例子,涉及map,collect,forEach函數

List<String> wordList = Arrays.asList("a", "b", "c");
//map把留轉換爲一個新的對象返回,collect收集器把流中的元素彙總
List<String> output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList());
output.forEach(System.out::println);

map的使用,它的做用就是把 input Stream 的每個元素,映射成 output Stream 的另一個元素。ui

collect:是一個終端操做,它接收的參數是將流中的元素累積到彙總結果的各類方式(稱爲收集器)spa

預約義收集器包括將流元素歸約和彙總到一個值.以下

工廠方法

返回類型

用於

toList

List<T>

把流中全部元素收集到List中

示例:List<Menu> menus=Menu.getMenus.stream().collect(Collector.toList())

toSet

Set<T>

把流中全部元素收集到Set中,刪除重複項

示例:Set<Menu> menus=Menu.getMenus.stream().collect(Collector.toSet())

toCollection

Collection<T>

把流中全部元素收集到給定的供應源建立的集合中

示例:ArrayList<Menu> menus=Menu.getMenus.stream().collect(Collector.toCollection(ArrayList::new))

Counting

Long

計算流中元素個數

示例:Long count=Menu.getMenus.stream().collect(counting);

SummingInt

Integer

對流中元素的一個整數屬性求和

示例:Integer count=Menu.getMenus.stream().collect(summingInt(Menu::getCalories))

averagingInt

Double

計算流中元素integer屬性的平均值

示例:Double averaging=Menu.getMenus.stream().collect(averagingInt(Menu::getCalories))

Joining

String

鏈接流中每一個元素的toString方法生成的字符串

示例:String name=Menu.getMenus.stream().map(Menu::getName).collect(joining(「, 」))

maxBy

Optional<T>

一個包裹了流中按照給定比較器選出的最大元素的optional
若是爲空返回的是Optional.empty()

示例:Optional<Menu> fattest=Menu.getMenus.stream().collect(maxBy(Menu::getCalories))

minBy

Optional<T>

一個包裹了流中按照給定比較器選出的最大元素的optional
若是爲空返回的是Optional.empty()

示例: Optional<Menu> lessest=Menu.getMenus.stream().collect(minBy(Menu::getCalories))

Reducing

歸約操做產生的類型

從一個做爲累加器的初始值開始,利用binaryOperator與流中的元素逐個結合,從而將流歸約爲單個值

示例:int count=Menu.getMenus.stream().collect(reducing(0,Menu::getCalories,Integer::sum));

collectingAndThen

轉換函數返回的類型

包裹另外一個轉換器,對其結果應用轉換函數

示例:Int count=Menu.getMenus.stream().collect(collectingAndThen(toList(),List::size))

groupingBy

Map<K,List<T>>

根據流中元素的某個值對流中的元素進行分組,並將屬性值作爲結果map的鍵

示例:Map<Type,List<Menu>> menuType=Menu.getMenus.stream().collect(groupingby(Menu::getType))

partitioningBy

Map<Boolean,List<T>>

根據流中每一個元素應用謂語的結果來對項目進行分區

示例:Map<Boolean,List<Menu>> menuType=Menu.getMenus.stream().collect(partitioningBy(Menu::isType));

forEach 方法接收一個 Lambda 表達式,而後在 Stream 的每個元素上執行該表達式。

filter的使用

Integer[] sixNuMS = {1, 2, 3, 4, 5, 6};
List<Integer> evens = Stream.of(sixNuMS).filter(n->n%2==0).collect(Collectors.toList());
evens.forEach(System.out::println);

 

reduce的使用

//拼接字符串
String concact = Stream.of("A","B","C","D").reduce("",String::concat);
System.out.println(concact);
//求最小值
double minValue = Stream.of(1.5,1.0,2.0,-3.0,-2.1).reduce(Double.MAX_VALUE,Double::min);
System.out.println(minValue);
//求和
int sumValue = Stream.of(1,2,3,4).reduce(Integer::sum).get();
System.out.println(sumValue);

這個方法的主要做用是把 Stream 元素組合起來。它提供一個起始值(種子),而後依照運算規則(BinaryOperator),和前面 Stream 的第一個、第二個、第 n 個元素組合

 

sorted的使用

List<Integer> list = Arrays.asList(1, 5, 7, 9, 3, 4);
List<Integer> list2 = list.stream().sorted((a, b) -> a.compareTo(b)).limit(4).collect(Collectors.toList());
System.out.println(list2);

對 Stream 的排序經過 sorted 進行,它比數組的排序更強之處在於你能夠首先對 Stream 進行各種 map、filter、limit、skip 甚至 distinct 來減小元素數量後,再排序,這能幫助程序明顯縮短執行時間。

 

match 的使用

List<Integer> list = Arrays.asList(1, 5, 7, 9, 3, 4);
boolean all = list.stream().allMatch(n -> n > 10);
System.out.println(all);
boolean any = list.stream().anyMatch(n -> n > 10);
System.out.println(any);
boolean none = list.stream().noneMatch(n -> n > 10);
System.out.println(none);

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

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

 

 

 

總結

總之,Stream 的特性能夠概括爲:

  • 不是數據結構
  • 它沒有內部存儲,它只是用操做管道從 source(數據結構、數組、generator function、IO channel)抓取數據。
  • 它也毫不修改本身所封裝的底層數據結構的數據。例如 Stream 的 filter 操做會產生一個不包含被過濾元素的新 Stream,而不是從 source 刪除那些元素。
  • 全部 Stream 的操做必須以 lambda 表達式爲參數
  • 不支持索引訪問
  • 你能夠請求第一個元素,但沒法請求第二個,第三個,或最後一個。不過請參閱下一項。
  • 很容易生成數組或者 List
  • 惰性化
  • 不少 Stream 操做是向後延遲的,一直到它弄清楚了最後須要多少數據纔會開始。
  • Intermediate 操做永遠是惰性化的。
  • 並行能力
  • 當一個 Stream 是並行化的,就不須要再寫多線程代碼,全部對它的操做會自動並行進行的。
  • 能夠是無限的
    • 集合有固定大小,Stream 則沒必要。limit(n) 和 findFirst() 這類的 short-circuiting 操做能夠對無限的 Stream 進行運算並很快完成。
相關文章
相關標籤/搜索