流操作应用于列表元素的顺序是什么?

Dra*_*vic 10 java java-8 java-stream

假设我们有一个标准的流操作方法链:

Arrays.asList("a", "bc", "def").stream()
  .filter(e -> e.length() != 2)
  .map(e -> e.length())
  .forEach(e -> System.out.println(e));
Run Code Online (Sandbox Code Playgroud)

JLS中是否有关于流操作应用于列表元素的顺序的保证?

例如,是否保证:

  1. 在应用过滤谓词"bc"之前,不会发生应用过滤谓词"a"
  2. 在应用映射函数"def"之前,应用映射函数是不会发生的"a"
  3. 1将在之前打印3

注意:我在这里专门讨论stream(),而不是 parallelStream()预期映射和过滤等操作并行完成的地方.

Yas*_*jaj 9

您可以在java.util.streamJavaDoc中找到您想知道的所有内容.

订购

流可能有也可能没有已定义的遭遇顺序.流是否具有遭遇顺序取决于源和中间操作.某些流源(例如List或数组)本质上是有序的,而其他流(例如HashSet)则不是.某些中间操作(例如sorted())可能会在其他无序流上强制执行遭遇顺序,而其他中间操作可能会呈现无序的有序流,例如BaseStream.unordered().此外,一些终端操作可以忽略遭遇顺序,例如forEach().

如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作; 如果流的源是包含[1,2,3]的List,那么执行map(x - > x*2)的结果必须是[2,4,6].但是,如果源没有定义的遭遇顺序,那么值[2,4,6]的任何排列都将是有效的结果.

对于顺序流,遭遇顺序的存在与否不会影响性能,只影响确定性.如果订购了流,则在相同的源上重复执行相同的流管道将产生相同的结果; 如果没有订购,重复执行可能会产生不同的结果.

对于并行流,放宽排序约束有时可以实现更高效的执行.如果元素的排序不相关,则可以更有效地实现某些聚合操作,例如过滤重复(distinct())或分组缩减(Collectors.groupingBy()).类似地,与遇到订单本质上相关的操作(例如limit())可能需要缓冲以确保正确排序,从而破坏并行性的好处.在流具有遭遇顺序但用户不特别关心该遭遇顺序的情况下,使用无序()明确地对流进行排序可以改善某些有状态或终端操作的并行性能.然而,大多数流管道,例如上面的"块的权重总和"示例,即使在排序约束下仍然有效地并行化.

  • @DraganBozanovic有'forEach`和`forEachOrdered`:后者将保持接触顺序.请参阅此问题http://stackoverflow.com/questions/29216588/how-to-ensure-order-of-processing-in-java8-streams (2认同)