java - 第三个参数 Java8 reduce on Object 中的字符串属性

标签 java lambda java-8 java-stream reduce

Stream Guru 的问题很简单:

我有这个:

    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> 它基本上表示对两个相同类型的操作数 的操作,产生与操作数相同类型的结果。在你的第二个代码片段中没有遵守这个契约(Contract)作为你的 map操作返回 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-interferingstateless .如果不考虑这一点,您的结果将是非确定性任意结果。

编辑:

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(", "));

关于java - 第三个参数 Java8 reduce on Object 中的字符串属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47541611/

相关文章:

c++ - 通过引用捕获与移动,Lambdas

c# - 如何在 Devforce 中组合 2 个不同类型的 c# 表达式?

java - Java 8 中对多维数组的方法引用

lambda - 映射结果上的 Collectors.groupingBy 到嵌套映射

java - 使用 logback 附加程序查找日志文件

java - 易变的背负式。这足以提高知名度吗?

autocomplete - ReSharper在lambda表达式中具有匿名类型的自动完成行为

performance - Java 8,列表的第一次处理比后续处理慢

java - java访问文件时出现错误

java - 使用netbeans中的JTable通过鼠标单击事件更新mySQL数据库中的数据