问题很简单:为什么我们不能在流中的操作中使用StringBuilder(...)
as ,而可以将其用作??identity function
reduce(...)
java8
string1.concat(string2)
identity function
string1.concat(string2)
可以被视为类似于builder.append(string)
(尽管据了解,这些操作之间几乎没有差异),但是我无法理解reduce操作中的差异。考虑以下示例:
List<String> list = Arrays.asList("1", "2", "3");
// Example using the string concatenation operation
System.out.println(list.stream().parallel()
.reduce("", (s1, s2) -> s1 + s2, (s1, s2)->s1 + s2));
// The same example, using the StringBuilder
System.out.println(list.stream() .parallel()
.reduce(new StringBuilder(""), (builder, s) -> builder
.append(s),(builder1, builder2) -> builder1
.append(builder2)));
// using the actual concat(...) method
System.out.println(list.stream().parallel()
.reduce("", (s1, s2) -> s1.concat(s2), (s1, s2)->s1.concat(s2)));
这是执行上述几行后的输出:
123
321321321321 // output when StringBuilder() is used as Identity
123
builder.append(string)
按原样str1.concat(str2)
是一个关联操作。那为什么能concat
工作append
却没有呢?
是的,append
是确实的关联,但这并不是由于储液器和组合传递函数的唯一要求。根据文档,它们必须是:
append
不是无国籍的。这是有状态的。当你这样做sb.append("Hello")
,它不仅返回一个StringBuilder
与Hello
追加到末尾,它也改变了内容的(即状态) sb
。
另外从文档:
如果流操作的行为参数是有状态的,则流管道结果可能不确定或不正确。有状态的lambda(或其他实现适当功能接口的对象)是一种有状态的lambda,其结果取决于在流管道执行期间可能更改的任何状态。
同样由于这个原因new StringBuilder()
,一旦应用了累加器或组合器,它就不是有效的标识。空字符串生成器中将添加一些内容,并且所有身份必须满足的以下方程式不再满足:
combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
并行流有可能在调用累加器和/或组合器之后使用旧的字符串生成器,并期望它们的内容不会更改。但是,累加器和组合器会使字符串生成器发生变异,从而导致流产生不正确的结果。
另一方面,concat
满足上述所有三个条件。它是无状态的,因为它不会更改调用它的字符串。它只是重新调整了一个新的串联字符串。(String
反正是不变的,不能更改:D)
无论如何,这是一个可变还原的用例collect
:
System.out.println((StringBuilder)list.stream().parallel()
.collect(
StringBuilder::new,
StringBuilder::append,
StringBuilder::append
)
);
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句