Java 为什么在以可变对象作为标识的并行流中调用reduce方法不会保留结果中的顺序?
有以下看似“正确”的代码:Java 为什么在以可变对象作为标识的并行流中调用reduce方法不会保留结果中的顺序?,java,java-8,java-stream,reduce,forkjoinpool,Java,Java 8,Java Stream,Reduce,Forkjoinpool,有以下看似“正确”的代码: List List=Arrays.asList(“1”、“2”、“3”、“4”、“5”、“6”, "7","8","9","10","11","12"); 字符串结果=list.parallelStream() .reduce(新的StringBuilder(),StringBuilder::append, StringBuilder::append).toString(); 系统输出打印项次(结果); 此代码段的问题是reduce方法调用中的标识new Strin
List List=Arrays.asList(“1”、“2”、“3”、“4”、“5”、“6”,
"7","8","9","10","11","12");
字符串结果=list.parallelStream()
.reduce(新的StringBuilder(),StringBuilder::append,
StringBuilder::append).toString();
系统输出打印项次(结果);
此代码段的问题是reduce
方法调用中的标识new StringBuilder()
是可变的,因此结果
被破坏,即结果
的顺序不保留。但我无法完全理解原因,因此我无法想象以与原始列表不同的顺序生成结果的情况。因此,我绘制了相应的map reduce图,它碰巧得到了保持顺序的结果
:
问题:首先,我想确认这个图表是正确的。其次,如果这个图是正确的,我想知道这个代码片段不总是产生结果的原因在哪里
保持顺序您的图是不正确的-您假设每个并行缩减都从一个新的StringBuilder开始。而不是使用相同的标识元素开始,即使用相同的StringBuilder(您创建并作为第一个参数传递给reduce
方法的元素)
每个并行流都调用StringBuilder.append
,对传递给reduce
方法的(一个也是唯一的)StringBuilder进行追加,从而将当前遇到的元素追加到它
下一步是组合部分结果,也可以通过在同一个StringBuilder上调用StringBuilder.append
,将StringBuilder内容的副本附加到自身
要创建绘制的图表,必须将供应商
作为第一个参数传递给reduce操作
实际上,根据霍尔格的评论,这在使用时是可能的
为此,您不调用reduce方法,而是调用collect
方法:
List<String> list = Arrays.asList("1","2","3","4","5","6",
"7","8","9","10","11","12");
String result = list.parallelStream()
.collect(StringBuilder::new, StringBuilder::append,
StringBuilder::append).toString();
System.out.println(result);
List List=Arrays.asList(“1”、“2”、“3”、“4”、“5”、“6”,
"7","8","9","10","11","12");
字符串结果=list.parallelStream()
.collect(StringBuilder::new、StringBuilder::append、,
StringBuilder::append).toString();
系统输出打印项次(结果);
非常感谢!:)这就是我想知道的(Y)应该注意的是,支持这样的可变容器正是我们要做的,所以.collect(StringBuilder::new,StringBuilder::append,StringBuilder::append)。toString()
完成了这项工作。这与collect(Collectors.joining())
完全相同。感谢您的提示:)@霍尔格:谢谢你提供的信息。我已经把它包括在我的答案里了
List<String> list = Arrays.asList("1","2","3","4","5","6",
"7","8","9","10","11","12");
String result = list.parallelStream()
.collect(StringBuilder::new, StringBuilder::append,
StringBuilder::append).toString();
System.out.println(result);