第三个参数 Java8 reduce on 对象中的字符串属性

Third param Java8 reduce on string attribute in Object

流大师的问题很简单:

我有这个:

    List<MyBean> beans = new ArrayList<>();
    beans.add(new MyBean("tutu"));
    beans.add(new MyBean("toto"));
    beans.add(new MyBean("titi"));

比较:

 StringBuilder reduced
            = beans.parallelStream()
                    .map(MyBean::getName)
                    .reduce(new StringBuilder(), (builder, name) -> {
                        if (builder.length() > 0) {
                            builder.append(", ");
                        }

                        builder.append(name);
                        return builder;
                    }, (left, right) -> left.append(right));

 StringBuilder reduced
            = beans.parallelStream()
                    .map(MyBean::getName)
                    .reduce(new StringBuilder(), (builder, name) -> {
                        if (builder.length() > 0) {
                            builder.append(", ");
                        }

                        builder.append(name);
                        return builder;
                    }/* WITHOUT THIRD PARAM*/);

为什么,第二个解决方案无法编译...第三个参数用于并行流...

你能解释一下为什么我无法编译第二个代码部分吗?

此行为是因为 reduce:

的重载
reduce(T identity, BinaryOperator<T> accumulator)

有两个参数,第二个是 BinaryOperator<T>,它基本上表示对 两个相同类型的操作数 的操作产生与操作数相同类型的结果。在你的第二个代码片段中没有遵守这个合同,因为你的 map 操作 returns a Stream<String>identity 是类型 StringBuilder .为防止编译器错误,只需将 identity 值和 accumulator 函数的操作数设为相同类型即可,即:

StringBuilder reduced
                = beans.stream()
                .map(b -> new StringBuilder(b.getName()))
                .reduce(new StringBuilder(), (builder, name) -> {
                    if (builder.length() > 0) {
                        builder.append(", ");
                    }

                    builder.append(name);
                    return builder;
                }/* WITHOUT THIRD PARAM*/);

另一方面,reduce 的重载:

reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

接受一个 BiFunction 作为第二个参数,它可以消耗 两种不同类型的对象 因此为什么你的第一个代码片段在没有编译器错误的情况下工作。

最后,不要忘记将 beans.parallelStream() 更改为 beans.stream(),如上面的解决方案所示。

顺便说一句,请注意,在并行执行操作时,累加器以及组合器必须associative, non-interfering and stateless。如果不考虑这一点,您的结果将是 nondeterministic 任意结果。

编辑:

Holger所述:

Modifying incoming parameters in a reduction function is broken by definition, even if it happens to produce the intended outcome in a sequential context. It also violates the contract of the first parameter, as the modified StringBuilder is not an identity value anymore. You can use Reduction with immutable values, as .map(MyBean::getName).reduce((a,b) -> a + ", " + b).orElse(""); or use Mutable Reduction like .map(MyBean::getName).collect(Collectors.joining(", "));