TL; DR; 我正在寻找一个可以查找某个中间操作或终端操作的地方。我在哪里可以找到这样的文件?
修改这不是How to ensure order of processing in java8 streams?的重复,因为该问题不提供全面的操作列表。
流是否具有遭遇顺序取决于源和中间操作
在this excellent stackoverflow answer
中重复了这一点为了确保整个流操作中的订购维护,您必须研究流的源文档,所有中间操作和终端操作,以确定它们是否维护订单(或者源是否有订购首先)。
这一切都很好,但我应该查看哪些文档? the package documentation在一个示例中提到map
保证排序,但它没有详尽的列表。 javadoc for the Stream class记录了一些中间操作,但不是全部。
以map
:
返回一个流,该流包含将给定函数应用于此流的元素的结果。
这是一个中间操作。
返回一个流,该流由与该给定谓词匹配的此流的元素组成。
这是一个中间操作。
这些都没有描述它们是否保留了排序。
实际上,每个中间操作都会默认保留订单。唯一的例外是:
- unordered(),用于删除排序约束。
- sorted()改变顺序。
如果没有明确指定,您可以假设操作保持订单。即使distinct()保持顺序,但它为并行流增加了很多复杂性。
但是有任何官方文件可以支持吗?
实际上有两个单独的排序问题。
例如,并行map
操作可以以任意顺序遍历所有元素(违反2.),但仍然保持返回流中的顺序(服从1)。
答案 0 :(得分:17)
在对源代码进行一些研究之后,我总结了以下表格:
取自:Java streams - Part 6 - Spliterator
下表显示了允许哪些操作类型修改字符:
| | 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 |
取自Java streams - Stream methods characteristics table
下表显示了每个中间操作 / 终端操作可以打开和关闭的特征和标志:( SHORT_CIRCUIT
仅在上下文中相关StreamOpFlag
标志)
注意:P
(保留)标记会添加到除C
和I
(清除和注入)标记之外的每个单元格。 < / p>
| | 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
- 注入。 答案 1 :(得分:1)
这听起来像两个重复 - 因为你联系的答案实际上都解释了事情。我无法判断map
或filter
是否应该明确说明他们保留了订单;他们不依赖任何之前的状态或任何其他状态(这些是无状态操作),所以暗示他们保留了我所看到的顺序。我反过来看,如果他们没有保留命令 - 应该在文档中明确提到;如果从操作的名称不明显。
例如Stream.generate
如果生成有序流,对我来说并不明显;因此,在它的文档中说:
另一方面,返回无限顺序无序流,其中每个元素由提供的供应商生成。
sorted
和unordered
非常明显(IMO)改变秩序,至少当你把它们放进去时 - 你明确地说你不关心订单。 unordered
顺便说一下,为了满足这一要求,我们不会随意进行任何随机化,您可以阅读更多here。
一般有两个订单:处理订单和遇到订单。
您可以将遭遇订单视为从左到右的处理(假设您有List
或array
)。因此,如果您有一个不改变顺序的管道 - 从左到右看,元素将被馈送到Collector
(或任何其他终端操作)。那么所有终端操作都不是这样的。一个明显的区别是forEach
和forEachOrdered
;或Collectors.toSet
- 根本不需要保留初始订单。或者让findAny
作为终端操作 - 显然你不关心你想要哪个元素,那么为什么要先按照一个确切的顺序来喂养findAny
呢? / p>
另一方面,
处理订单没有定义的顺序 - 显然对于并行处理尤其可见。因此,即使您的管道是并行的(并且在完全不保证任何订单的情况下处理元素),它们仍将按顺序馈送到终端操作 - 如果该终端操作需要这样的订单。