流的操做類型分爲兩種:java
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緩存
Short-circuiting:對一個無限及集合返回有限的數據 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limitbash
對象匹配過濾數據結構
方法 | 示意 |
---|---|
filter | 經過傳遞一個預期匹配的對象做爲參數並返回一個包含全部匹配到的對象的流。 |
distinct | 返回包含惟一元素的流(惟一性取決於元素相等的實現方式)。 |
limit | 返回一個特定上限的流 |
skip | 返回一個丟棄前n個元素的流 |
List expensiveInvoices
= invoices.stream()
.filter(inv -> inv.getAmount() > 10_000)
.limit(5)
.collect(Collectors.toList());
複製代碼
匹配是一個判斷是否匹配到給定屬性的廣泛的數據處理模式,表達式最後返回boolean架構
方法 | 示意 |
---|---|
allMacth | 流對象每一個都要匹配到 |
anyMatch | 流對象有匹配到就中斷 |
noneMatch | 流對象無匹配對象 |
boolean expensive =
invoices.stream()
.allMatch(inv -> inv.getAmount() > 1_000);
複製代碼
:流接口還提供了像findFirst和findAny等從流中取出任意的元素。它們能與像filter方法相鏈接。findFirst和findAny都返回一個可選對象,在串行流中二者都是返回第一個對象,在並行流中findAny返回第一個線程處理最快的數據app
方法 | 示意 |
---|---|
findFirst | 返回第一個匹配到的對象 |
findAny | 返回第一個匹配到的對象 |
Optional =
invoices.stream()
.filter(inv ->
inv.getCustomer() == Customer.ORACLE)
.findAny();
複製代碼
:流支持映射方法,傳遞一個函數對象做爲方法,把流中的元素轉換成另外一種類型。這種方法應用於單個元素,將其映射成新元素。框架
方法 | 示意 |
---|---|
map | 應用於單個元素,將其映射成新元素。 |
List ids
= invoices.stream()
.map(Invoice::getId)
.collect(Collectors.toList());
複製代碼
方法 | 示意 |
---|---|
reduce(BinaryOperator) | 一個函數主要用於累和,求最大值。 |
int product = numbers.stream().reduce(1, (a, b) -> a * b);
int max = numbers.stream().reduce(Integer.MIN_VALUE,
Integer::max);
複製代碼
forEach Terminal操做,再也不返回stream對象,forEach循環體內不能修改本身包含的本地變量值,也不能用 break/return 之類的關鍵字提早結束循環。 peek能夠對循環對象二次封裝並返回新的對象ide
sorted
它比數組的排序更強之處在於你能夠首先對 Stream 進行各種 map、filter、limit、skip 甚至 distinct 來減小元素數量後,再排序,這能幫助程序明顯縮短執行時間。函數
List<Person> persons = new ArrayList();
for (int i = 1; i <= 5; i++) {
Person person = new Person(i, "name" + i);
persons.add(person);
}
List<Person> personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
System.out.println(personList2);
複製代碼
獲取最後計算的最小值,最大值和去重複
目前爲止你所瞭解的方法都是返回另外一個流或者一個像boolean,int類型的值,或者返回一個可選對象。相比之下,collect方法是一個結束操做,它可使流裏面的全部元素彙集到彙總結果。 傳遞給collect方法參數是一個java.util.stream.Collector類型的對象。Collector對象實際上定義了一個如何把流中的元素彙集到最終結果的方法。最開始,工廠方法Collectors.toList()被用來返回一個描述瞭如何把流轉變成一個List的Collector對象。後來Collectors類又內建了不少類似的collectors變量。例如,你能夠用Collectors.groupingBy方法按消費者把發票分組
Map<Customer, List> customerToInvoices
= invoices.stream().collect(Collectors.group
ingBy(Invoice::getCustomer));
複製代碼
Map<Integer, List<Person>> personGroups = Stream.generate(new PersonSupplier()).
limit(100).
collect(Collectors.groupingBy(Person::getAge));
Iterator it = personGroups.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, List<Person>> persons = (Map.Entry) it.next();
System.out.println("Age " + persons.getKey() + " = " + persons.getValue().size());
}
複製代碼
在使用條件「年齡小於 18」進行分組後能夠看到,不到 18 歲的未成年人是一組,成年人是另一組。partitioningBy 實際上是一種特殊的 groupingBy,它依照條件測試的是否兩種結果來構造返回的數據結構,get(true) 和 get(false) 能即爲所有的元素對象。
方法 | 示意 |
---|---|
mapToInt | 函數體返回值爲int類型 |
mapToDouble | 函數體返回值爲Double類型。 |
mapToLong | 函數體返回值爲Long類型。 |
方法 | 示意 |
---|---|
flatMapToInt | 函數體返回值爲int類型 |
flatMapDouble | 函數體返回值爲Double類型。 |
flatMapLong | 函數體返回值爲Long類型。 |
Stream<List<Integer>> inputStream = Stream.of(
Arrays.asList(1),
Arrays.asList(2, 3),
Arrays.asList(4, 5, 6)
);
Stream<Integer> outputStream = inputStream.
flatMap((childList) -> childList.stream());
複製代碼
Stream API 支持方便的數據並行。換句話說,你能夠明確地讓流管道以並行的方式運行而不用關心底層的具體實現。在這背後,Stream API使用了Fork/Join框架充分利用了你機器的多核架構。 你所須要作的無非是用parallelStream()方法替換stream()方法。 不是全部的都使用並行的方式,以下