2017-08-31 33 views
11

TL; DR;我正在尋找一個地方,我可以查找某個中間或終端操作。我在哪裏可以找到這樣的文檔?Java Streams:哪些操作保存順序

背景

the package documentation說:

無論是否流具有一遇到順序取決於源和中間操作上

其在this excellent stackoverflow answer

重複

爲了確保在整個流操作中維護排序,您必須研究流源的文檔,所有中間操作和終端操作,以確定它們是否維持順序(或者源代碼是否首先排序)。

這一切都很好,但我應該看看哪些文檔? the package documentation在一個示例中提到map保證排序,但它沒有詳盡的列表。 javadoc for the Stream class記錄了一些中間操作,但不是全部。 就拿map

返回由施加給定函數此流中的元素的結果的流。

這是一箇中間操作。

filter

返回由該流匹配給定的謂詞的元素流。

這是一箇中間操作。

沒有一個描述它們是否保持排序。

This stackoverflow answer權利要求:

實際上每個中間操作保留默認順序。唯一的例外是:

  • unordered()它刪除排序約束。
  • sorted()它改變了順序。

如果未明確指定,則可以假定操作保持順序。即使distinct()也保持順序,儘管它爲並行流增加了很多複雜性。

但是是否有任何官方文件支持?

額外信貸

實際上有兩個單獨的訂購問題。

  1. 操作的輸出是否保持與輸入相同的順序?
  2. 操作是否按順序在每個元素上執行。

例如,並行map操作上可以繼續以任意順序的所有元素(違反2),但仍維持返回流中的順序(1服從)

+0

另請參見https://stackoverflow.com/a/29218074/32453 – rogerdpack

回答

7

後一些源代碼研究我summerized如下表:

來自Streams In Depth - Chapter 7: Spliterator

哪些操作類型允許修改charactersiticts下表showes:

|      | DISTICTS | SORTED | ORDERED | SIZED | SHORT_CIRCUIT | 
| ---------------------- | -------- | ------ | ------- | ----- | --------------| 
| source stream   | Y  | Y  | Y  | Y  | N    | 
| intermediate operation | PCI  | PCI | PCI  | PC | PI   | 
| terminal operation  | N  | N  | PC  | N  | PI   | 
  • Y - 允許有
  • P - 可能保留
  • C - 可能會清除。
  • I - 可以注射。
  • N - 無效;非常適合手術。

Streams In Depth - Stream methods characteristics table

下表showes每個中間操作/終端操作 5接通和斷開,其特徵和標誌摘自:(SHORT_CIRCUIT僅在StreamOpFlag上下文中相應和標誌)

注意:P(保留)標誌被添加到每除了具有CI(清除和注入)標誌的單元外。

|     | DISTINCT | SORTED | ORDERED | SIZED | SHORT_CIRCUIT | 
| ---------------- | ----------| --------| ---------| -------| ---------------| 
| filter   |   |   |   | C  |    | 
| forEach   |   |   | C  |  |    | 
| forEachOrdered |   |   |   |  |    | 
| allMatch  |   |   | C  |  | I    | 
| distinct  | I  |   |   | C  |    | 
| flatMap   | C  | C  |   | C  |    | 
| anyMatch  |   |   | C  |  | I    | 
| collect   |   |   |   |  |    | 
| unOrdered  |   |   | C  |  |    | 
| count   | C  | C  | C  | C  |    | 
| findAny   |   |   | C  |  | I    | 
| findFirst  |   |   |   |  | I    | 
| flatMapToXXX | C  | C  |   | C  |    | 
| limit   |   |   |   | C  | I    | 
| map    | C  | C  |   |  |    | 
| mapToXXX  | C  | C  |   |  |    | 
| max    |   |   |   |  |    | 
| min    |   |   |   |  |    | 
| noneMatch  |   |   | C  |  | I    | 
| peek   |   |   |   |  |    | 
| reduce   |   |   |   |  |    | 
| skip   |   |   | C  | I  |    | 
| sorted   |   | I  | I  |  |    | 
| toArray   |   |   |   |  |    | 
  • C - 清除。
  • I - 注射。
+0

我修復了其中一些標誌;首先,'forEach'和'forEachOrdered'之​​間的根本區別在於'forEach'不考慮每個合同的順序,即使當前實現可能不會在內部清除該標誌;這種設置/清除邏輯不適合終端操作。此外,沒有理由說明爲什麼元素的順序應該與'count'操作相關,順便說一句,在Java 9中可能會短路。並且說'sort'同時清除並注入'SORTED'沒有多大意義,尤其是,因爲它是穩定的... – Holger

+0

此表僅反映**實現的**當前狀態。 **爲什麼**他們是否在碼頭操作中注射/清除旗幟是一個不容忽視的問題,應該進行調查。感謝您的注意和編輯。 –

+1

好吧,有一種* unsorted *終端操作的反向傳播到流管道,它可能影響操作,但是它更復雜, 'Collector'可以是['UNORDERED'](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.Characteristics.html#UNORDERED),因此,一個'collect操作可能會將* unordered *狀態傳播到流管道。對於其他特徵,終端操作是否可以利用它會更有趣,例如, 'toArray'將受益於'SIZED'特性,'count'將在Java 9中受到... – Holger

1

這有點聽起來像兩個重複 - 因爲你鏈接的答案實際上解釋了事情。我不知道mapfilter應該專門說他們保存順序;他們不依賴任何先前的狀態或任何其他狀態(這些是無狀態操作),因此它是暗示,他們保持順序,據我所知。我反過來看,如果他們不保留秩序 - 應該在文檔中明確提及;如果從操作的名稱不明顯。 例如Stream.generate對我來說並不明顯,如果它生成一個有序的流;因此這在文檔中有說明:

返回一個無限順序無序流,其中每個元素都由提供的供應商生成。

sortedunordered,另一方面是相當明顯的(IMO)更改訂單,至少當你把這些 - 你明確地說,你不關心順序。 unordered順便說一句,不會有目的的任何隨機,以滿足這一點,你可以閱讀更多here

一般有兩個訂單:處理訂單遇到訂單

你可以想想遭遇訂單加工由左到右(想象你有Listarray)。所以如果你有一個不改變順序的流水線 - 元素將會從左到右看到Collector(或任何其他的終端操作)。那麼不是所有的終端操作都是這樣的。一個明顯的區別是forEachforEachOrdered;或者Collectors.toSet - 根本不需要保存初始訂單。或者讓我們以findAny作爲終端操作 - 顯然你並不關心你想要哪個元素,那麼爲什麼要按照確切的順序餵養findAny呢?

另一方面,處理訂單沒有明確的順序 - 顯然對於並行處理尤其明顯。因此,即使您的管道是並行的(並且元素的處理絕對不能保證任何順序),它們仍然會按順序饋送到終端操作 - 如果此終端操作需要這樣的順序。

+0

我會走到目前爲止,說*返回*無序*流的每個*方法記錄爲這樣。這也適用於'unordered()',它的文檔指出它返回一個無序的流,而'sorted()'確實遵守遇到順序,因爲它將對有序流使用穩定的排序。 – Holger