JAVA8已經發布了八年多,但2014年發布的許多特性都延續到了2022年。其中最突出的是Java流。在這篇文章中,我們解釋了什么是Java流,解釋了何時使用它們。并簡要介紹了常見的Java流操作。
Java中的流是什么?
Java流支持對元素流的函數式操作。流是以某種順序應用于數據的不可變函數集合的抽象。流不是可以存儲元素的集合。
流和結構之間最重要的區別是流不保存數據。例如,你不能指向流中某個元素存在的位置。你只能指定對該數據進行操作的函數。并且在流上執行操作時,會影響原流。
注意,這個文章中的流不要與Java I/O包中的流混淆,如InputStream、OutputStream等。
何時使用Java流
Java流代表了數據流動的管道和對數據進行操作的函數。在這種情況下,管道由一個流源、零個或多個中間操作以及一個終端操作組成。因此,流可以用在任何涉及數據驅動函數的應用程序中。
在下面的例子中,Java流被用作一個奇特的迭代器:
在這個例子中,我們只選擇偶數值,通過使用過濾器方法,并將它們增加了一倍繪圖使輸入加倍的函數。這給我們提供了什么?streams API為我們提供了在各個步驟中指定數據操作序列的能力。我們不指定任何條件處理代碼,我們不想編寫大型復雜函數,我們不關心數據流。
事實上,我們一次只為一個數據處理步驟而煩惱:我們通過streams框架的能力自己組合函數和通過函數的數據流。上面的例子顯示了你最終將在流中使用的最重要的模式之一:
將集合提升到流。
騎流:過濾值,轉換值,限制輸出。
組成小的個體操作。
將結果收集回具體的集合中。
流中的常見操作
在Java 8及更高版本中,你可以通過調用stream()方法輕松地從任何集合中獲取流。之后,還有幾個你會經常遇到的基本函數。
以下是Java流中的一些常見操作:
過濾器:返回一個新流,其中包含原始流的一些元素。它接受謂詞來計算應該在新流中返回哪些元素,并刪除其余的元素。在命令式代碼中,我們會使用條件邏輯來指定應該發生什么如果一個元素滿足條件。在功能性的風格中,我們不用費心可安裝文件系統,我們過濾流,只處理我們需要的值。
地圖:將流元素轉換成其他東西,它接受一個應用于流中每個元素的函數,并返回參數函數產生的值的流。這是Java流API的基礎。Map允許你對流中的數據執行計算。
減少:(有時也稱為折疊)將流簡化為單個元素。如果你想要對流中的所有整數值求和,你需要使用reduce函數。如果你想在流中找到最大值,reduce就是你的朋友。
收集:這是走出流世界并獲得具體的值集合的方法,就像上面例子中的列表一樣。
你不會在每次遇到流時都使用所有這些函數,但是你可以隨意使用它們。
關于Java Streams API的最終想法
并行運行每個流操作存在缺陷,大多數streams實現使用默認的ForkJoinPool在后臺執行操作。因此,你可以很容易地使特定的流處理稍微快一點,但是卻犧牲了整個JVM的性能,甚至沒有意識到這一點。
使用函數式編程解決問題需要不同的思維方式。但是通過一點試驗,你就能掌握它的竅門。
通常,你可能很難找到一個實用的解決方案,但是一旦你得到了,你就會意識到它并不特別復雜。然后下一次解決類似的問題就容易多了。