我知道这些方法的执行顺序不同,但在我的所有测试中,我都无法实现不同的顺序执行.
例:
System.out.println("forEach Demo");
Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s));
System.out.println("forEachOrdered Demo");
Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s));
Run Code Online (Sandbox Code Playgroud)
输出:
forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC
Run Code Online (Sandbox Code Playgroud)
请提供两种方法产生不同输出的示例.
规范是否保证顺序 Java Streams 上的所有操作都在当前线程中执行?("forEach"和"forEachOrdered"除外)
我明确要求规范,而不是当前的实现.我可以自己查看当前的实现,不需要打扰你.但实现可能会改变,还有其他实现.
我问因为ThreadLocals:我使用的是一个内部使用ThreadLocals的Framework.即使像company.getName()这样的简单调用最终也会使用ThreadLocal.我无法改变该框架的设计方式.至少不在理智的时间内.
这里的规范似乎令人困惑.包"java.util.stream"的文档说明:
如果行为参数确实有副作用,除非明确说明,否则不能保证这些副作用对其他线程的可见性,也不保证同一流管道中"相同"元素的不同操作在同一个线程中执行.
...
即使当管道被约束以产生结果,其与流源的遭遇顺序一致(例如,IntStream.range(0,5).parallel()地图(X - > X*2).toArray( )必须产生[0,2,4,6,8]),不能保证制成,以作为对于所述映射器函数被应用到各个元件,或为了在什么螺纹任何行为参数被执行对于给定的元件.
我将其解释为:流上的每个操作都可以在不同的线程中发生.但是"forEach"和"forEachOrdered"的文档明确指出:
对于任何给定元素,可以在任何时间以及库选择的任何线程中执行该动作.
如果每个流操作都可能发生在未指定的线程中,那么该语句将是多余的.因此恰恰相反:串行流上的所有操作都保证在当前线程中执行,除了"forEach"和"forEachOrdered"?
我搜索了关于"Java","Stream"和"ThreadLocal"组合的权威答案,但没有发现任何内容.该关闭的事情是由一个答案作者Brian Goetz在这里对堆栈溢出一个相关的问题,但它是有关订单,而不是线程,它只是对"的forEach",而不是其他流的方法:是否Stream.forEach尊重遇到顺序流的顺序?
是否有一个操作的任何保证连续和有序流的处理,在遭遇订单?
我的意思是,如果我有这样的代码:
IntStream.range(0, 5)
.map(i -> {
myFunction(i);
return i * 2;
})
.boxed()
.collect(toList());
Run Code Online (Sandbox Code Playgroud)
是否有保证,它将以生成范围的遭遇顺序执行myFunction()调用?
我找到了Stream类的JavaDocs草案,明确说明了这一点:
对于顺序流管道,如果管道源具有已定义的遭遇顺序,则所有操作都以管道源的遭遇顺序执行.
但在官方JavaDocs中,这一行被删除了.它现在仅讨论所选方法的遭遇顺序.该包装java.util.stream文档的副作用款规定:
即使管道被约束以产生与流源的遭遇顺序一致的结果(例如,
IntStream.range(0,5).parallel().map(x -> x*2).toArray()必须产生[0, 2, 4, 6, 8]),也不保证将映射器函数应用于各个元素的顺序,或者什么线程为给定元素执行任何行为参数.
但它没有说明顺序流,而且这个例子是针对并行流的(我的理解是顺序流和并行流都是如此,但这是我不确定的部分).
另一方面,它也在订购部分说明:
如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作; 如果流的源是
List包含的[1, 2, 3],那么执行的结果map(x -> x*2)必须是[2, 4, 6].但是,如果源没有定义的遭遇顺序,则值的任何排列[2, 4, 6]都将是有效结果.
但这一次它以"对元素进行操作"开始,但是示例是关于产生的流,所以我不确定它们是否会考虑副作用,副作用实际上就是这个问题.
在阅读有关流的文档时,我遇到了以下句子:
...试图从行为参数中访问可变状态会给你一个错误的选择...如果你没有同步访问那个状态,你就有数据竞争,因此你的代码被破坏...... [1]
如果行为参数确实有副作用...... [没有]保证在同一个线程中执行同一流管道中"相同"元素的不同操作.[2]
对于任何给定元素,可以在任何时间以及库选择的任何线程中执行该动作.[3]
这些句子不区分顺序流和并行流.所以我的问题是:
我有一个ListA,B,C.
C reduce A reduce B != A reduce B reduce C (但是,减少(B减少C)是可以的).
换句话说,我的还原操作是关联的,但不是可交换的.
java是否对有序顺序流(例如列表中的默认流)执行减少将始终根据遭遇顺序进行减少?也就是说,java会重新排序减少(这样B减少A而不是A减少B)?
(希望这很清楚).
编辑添加一个小演示,也许有助于澄清
Stream.of(" cats ", " eat ", " bats ")
.reduce("", (a, b) -> a + b); // cats eat bats
Run Code Online (Sandbox Code Playgroud)
有了上述,输出可能是"蝙蝠猫吃"或"吃蝙蝠猫"?是否在规范的某处保证了?
list.stream().forEach(e -> { dbCall.delete(e.Id());});
列表中的每一项都会从数据库中删除。
假设列表中有3项,如何进行单元测试:
前提:我已经阅读了这个问题和其他问题,但我需要一些澄清。
我知道该Stream.forEach方法在处理并行流时(不仅)有所不同,这解释了为什么
//1
Stream.of("one ","two ","three ","four ","five ","six ")
.parallel()
.forEachOrdered(item -> System.out.print(item));
Run Code Online (Sandbox Code Playgroud)
印刷
one two three four five six
Run Code Online (Sandbox Code Playgroud)
但是当涉及到中间操作时,当流并行化时,顺序就不再保证了。所以这段代码
//2
Stream.of("one ","two ","three ","four ","five ","six ")
.parallel()
.peek(item -> System.out.print(item))
.forEachOrdered(item -> System.out.print(""));
Run Code Online (Sandbox Code Playgroud)
会打印类似的东西
four six five one three two
Run Code Online (Sandbox Code Playgroud)
说该forEachOrdered方法仅影响其自身执行中的元素顺序是否正确?直觉上,我认为//1示例与
//3
Stream.of("one ","two ","three ","four ","five ","six ")
.parallel()
.peek(item -> System.out.print("")) //or any other intermediate operation
.sequential()
.forEach(item -> System.out.print(item));
Run Code Online (Sandbox Code Playgroud)
难道是我的直觉错了?我是否遗漏了整个机制的某些内容?
在处理Java项目时,我遇到了如下所示的代码:
someMap.keySet().stream().sorted().forEach(/* ... */);
Run Code Online (Sandbox Code Playgroud)
根据键的自然顺序,这里的意图显然是为地图中的每个键做一些事情,这似乎是在实践中发生的事情.但是,我不确定这种行为是否得到保证.Javadoc for Stream#forEach说:
此操作的行为明确是不确定的.对于并行流管道,此操作不保证遵守流的遭遇顺序,因为这样做会牺牲并行性的好处.对于任何给定元素,可以在任何时间以及库选择的任何线程中执行该动作.
我知道如果代码使用.parallelStream()而.stream()不是保证它不能保证工作,但由于它使用的是顺序流(Javadoc没有说什么),我不确定.这是保证始终有效,还是代码需要使用.forEachOrdered()而不是.forEach()它?
编辑:我认为这个问题不是Java 8 Stream中forEach vs forEachOrdered的重复,因为这个问题是"一般来说forEach和forEachOrdered之间有什么区别的例子",并且接受的答案基本上是"并行流" .这个问题具体是关于顺序流.
从java 8开始迭代通过列表我可以使用两者:
List list = new ArrayList();
1. list.forEach(...)
2. list.stream().forEach(...)
Run Code Online (Sandbox Code Playgroud)
使用第二种情况有什么好处吗?要将列表转换为流?