在Java 8中的有序列表上进行映射

在Java 8附带的流式库中,我们提供了forEachOrdered API,其文档在此处转载

void forEachOrdered(消费者行为)

对此流的每个元素执行操作。

这是终端操作。

此操作一次一个地处理元素, 如果存在则以遭遇顺序处理在为后续元素执行操作之前,对一个元素执行操作 ,但对于任何给定元素,可以在库选择的任何线程中执行操作。

我们在地图API的订购方面有任何保证吗?

例如,我在代码中有以下内容

private final BazUtils bazUtils; public List getFoos(List bars) { AtomicInteger idx = new AtomicInteger(1); return bars.stream() .map(bar -> bazUtils.getFoo(bar, idx.getAndAdd(1))) .collect(Collectors.toList()); } 

在处理过程中是否会遵守bars顺序?

请参阅包文档 ,“无状态行为”和“副作用”部分:

…如果行为参数确实有副作用,除非明确说明,否则不能保证这些副作用对其他线程的可见性 ,也不保证同一流中“相同”元素的不同操作管道在同一个线程中执行。 此外,这些效果的排序可能令人惊讶。 即使管道被约束产生的结果与流源的遭遇顺序一致(例如, IntStream.range(0,5).parallel().map(x -> x*2).toArray()必须产生[0, 2, 4, 6, 8] ),不保证映射器函数应用于单个元素的顺序,或者对于给定元素执行任何行为参数的线程

换句话说,即使使用AtomicInteger ,您的示例也不会在使用并行流时起作用,因为没有关于处理顺序的保证。 流将保持遭遇顺序,即结果List的顺序将反映原始List Bar的原始顺序,但通过副作用生成的int值可能不匹配(并行性能可能很差,方式)。

forEachOrdered终端操作非常特殊,因为操作的处理顺序将与遭遇顺序匹配。 当使用此终端操作时,这将极大地限制并行处理的好处。

你可以做你想要的正确使用

 public List getFoos(List bars) { return IntStream.range(0, bars.size()) //you may add .parallel() .mapToObj(idx -> bazUtils.getFoo(bars.get(idx), idx+1)) .collect(Collectors.toList()); } 

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps

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

所以,是的; 订单由map保存。