作者:知秋
來源:重走Java基礎(chǔ)之Streams(一)
因為經(jīng)常逛stackoverflow
,最近也在看reactive和storm以及前一陣子也用流式ORM框架speedment
與Springboot
整合改造了migo2.0中的單點登錄,深深的感受到j(luò)ava8已經(jīng)融入我們很深了憔辫,尤其是Spring5對其進行大力支持,覺得有必要再對自己的知識整理一下慧邮,順帶就把stackoverflow
一些東西自己拿過來整理翻譯一下,里面也會加入一些自己的理解
Introduction
流表示一系列元素并支持不同類型的操作來對這些元素執(zhí)行計算。在Java 8中,Collection接口有兩種方法來生成Stream
- 1)stream()和
- 2) parallelStream()
流操作包括中間或終端。 中間操作返回一個流拉鹃,所以我們可以鏈接多個中間操作而不使用分號辈赋。 終端操作是void的或返回非流結(jié)果。
Examples
Using Streams
A Stream
是可以執(zhí)行順序和并行聚合操作的一系列元素 膏燕。 任何給定的“Stream”都可能有無限量的數(shù)據(jù)流過它钥屈。 你所得到的結(jié)果是從“Stream”接收的數(shù)據(jù)在到達時被單獨處理,而不是完全對數(shù)據(jù)執(zhí)行批處理坝辫。 當與lambda表達式 結(jié)合時篷就,它們提供了使用函數(shù)方法對數(shù)據(jù)序列執(zhí)行操作的簡明方法。
Example: (see it work on Ideone)
Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange");
fruitStream.filter(s -> s.contains("a"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
Output:
APPLE
BANANA
ORANGE
PEAR
上述代碼執(zhí)行的操作可以總結(jié)如下:
使用靜態(tài)工廠方法
Stream.of(values)
創(chuàng)建一個包含fruitString
的順序排序Stream
的Stream
元素filter()
操作僅保留與給定謂詞(由謂詞返回true測試時的元素)匹配的元素近忙。 在這種情況下竭业,它保留含有“a”的元素智润。 謂詞作為lambda表達式給出。-
map()
操作轉(zhuǎn)換 每個元素使用給定的函數(shù)未辆,稱為映射器窟绷。 在這種情況下,每個fruitString
使用method-reference映射到將string字符串轉(zhuǎn)換為大寫版本String::toUppercase
咐柜。Note 如果映射函數(shù)返回與其輸入?yún)?shù)不同的類型兼蜈,那么
map()
操作將返回具有不同泛型類型的流。 例如在一個Stream
調(diào)用.map(String :: isEmpty)
返回一個Stream<Boolean>
sorted()
操作對Stream
的元素進行排序 根據(jù)它們的自然排序(根據(jù)在'String'的情況下對所在字典的順序拙友,其實都知道)为狸。最后,
forEach(action)
操作執(zhí)行一個動作遗契,作用于“Stream”的每個元素辐棒,將其傳遞給一個 Consumer。 在該示例中姊途,每個元素只是被打印到控制臺涉瘾。 該操作是終端操作,因此不可能再次進行操作捷兰。Note 在
Stream
中定義的操作之所以被執(zhí)行立叛,是因為最后有終端操作。 假如沒有終端操作贡茅,'Stream'將不被處理秘蛇,因為'Stream'輸出不被任何終端操作使用(省的浪費計算資源,所以很多書上稱之為被動式foreach)顶考。
操作(如上所示)鏈接在一起以形成可以被視為對數(shù)據(jù)的查詢
Reusing Streams
一個Stream
不能重復使用赁还。 一旦調(diào)用任何中間或終端操作,“Stream”對象將變得不可用驹沿。 Stream
代替地使用中間Stream
對象以便將中間操作鏈接在一起通過一系列Stream
操作來生成一個Stream
對象作為中間對象艘策,最后再調(diào)用這個生成的Stream
對象來完成最終的操作,最后一步的操作只能進行一次渊季,之后朋蔫,此流已經(jīng)沒了(生命周期已結(jié)束)。
Example:
Stream<String> stream =
Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> s.startsWith("a"));
stream.anyMatch(s -> true); // The Stream has been used and is now consumed.
stream.noneMatch(s -> true); // IllegalStateException; stream was already used
Closing Streams
Stream
接口擴展了 AutoCloseable
却汉。Streams可以通過調(diào)用 close
方法或使用try-with -resource語句來關(guān)閉驯妄。
請注意,Stream通常不必關(guān)閉合砂。僅需要關(guān)閉在IO通道上運行的流青扔。 大多數(shù)
Stream
型不對資源操作,因此不需要關(guān)閉。
Stream
應(yīng)該關(guān)閉的示例用例是微猖,當您從文件創(chuàng)建一個Stream
行時:
try(final Stream<String> lines = Files.lines(Paths.get("somePath"))){
lines.forEach(System.out::println);
}
Stream
接口也聲明了Stream.onClose()
方法谈息,它允許你注冊 Runnable
處理程序,當 流關(guān)閉励两。 一個示例用例是產(chǎn)生流的代碼需要知道它何時被消耗以執(zhí)行一些清理黎茎。
public Stream<String>streamAndDelete(Path path) throws IOException {
return Files.lines(path)
.onClose(()->someClass.deletePath(path));
}
運行處理程序只有在調(diào)用close()
方法時才會執(zhí)行,例如通過try-with-resources:
Path myPath = Paths.get("somePath");
try(final Stream<String> lines = streamAndDelete(myPath)){
lines.forEach(System.out::println);
}
Files.exists(myPath); // returns false
If close() isn't called, explicitly or implicitly, then the handler will not be called either:
如果沒有明確或隱式地調(diào)用close()
当悔,那么處理程序不會被調(diào)用:
streamAndDelete(myPath)
.forEach(System.out::println);
Files.exists(myPath); // returns true
Processing Order
Stream
對象的處理可以是順序或 parallel(并行)傅瞻。
在** sequential **模式中,按照“Stream”的源的順序處理元素盲憎。 如果Stream
是有序的(例如 SortedMap
實現(xiàn)或List
嗅骄,處理過程保證匹配源的排序。 然而饼疙,在其他情況下溺森,應(yīng)注意不要依賴于順序(參見:是Java的HashMap`` keySet()
迭代順序一致?)窑眯。
Example:
List<Integer> integerList = Arrays.asList(0, 1, 2, 3, 42);
// sequential
long howManyOddNumbers = integerList.stream()
.filter(e -> (e % 2) == 1).count();
System.out.println(howManyOddNumbers); // Output: 2
并行模式允許在多個核上使用多個線程屏积,但不能保證處理元素的順序。
如果在順序的 Stream
上雖然調(diào)用了多個方法磅甩,則不一定必須要調(diào)用每個方法炊林。 例如,如果一個 Stream
被過濾卷要,并且元素的數(shù)量減少到一渣聚,則不會發(fā)生對諸如sort
的方法的后續(xù)調(diào)用。 這可以提高順序的Stream
的性能 - 這是一個并行的Stream
不可能實現(xiàn)的優(yōu)化僧叉。
Example:
// parallel
long howManyOddNumbersParallel = integerList.parallelStream()
.filter(e -> (e % 2) == 1).count();
System.out.println(howManyOddNumbersParallel); // Output: 2