collectors.reducing方法在用作collectors.partitionby的下游时正在更新相同的标识

8ljdwjyq  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(514)

我有一个类似于下面的课程 MyObject .

public class MyObject {
    private String key; // not unique. multiple objects can have the same key.
    private boolean isPermanent;
    private double value1;
    private double value2;

    public MyObject merge(MyObject m){
        value1 += m.getValue1();
        value2 += m.getValue2();
        return this;
    }

    // getters, setters and constructors...
}

以下是示例数据:

List<MyObject> objs = new ArrayList<>();

objs.add(new MyObject("1", false, 100, 200));
objs.add(new MyObject("2", false, 300, 100));
objs.add(new MyObject("1", false, 200, 300));

objs.add(new MyObject("3", true, 100, 200));
objs.add(new MyObject("1", true, 500, 100));
objs.add(new MyObject("1", true, 100, 100));

我想根据 isPermanent 以及 key 并做了以下工作:
(请注意,我添加了 import static java.util.stream.Collectors.* 导入 groupingBy , partitioningBy 以及 reducing 在下面的代码中)

objs.stream()
    .collect(partitioningBy(MyObject::isPermanent,
                            groupingBy(MyObject::getKey,
                                       reducing(new MyObject(), MyObject::merge))));

返回的Map类型为 Map<Boolean, Map<String, MyObject>> . 我希望返回的Map如下(忽略除 value1 以及 value2 )

{false : { 1 : { 300, 500 } } , { 2 : { 300, 100 } }, true : { 1 : { 600, 200 } } , { 3 : { 100, 200 } } }

但我得到的结果是:

{false : { 1 : { 1300, 1000 } } , { 2 : { 1300, 1000 } }, true : { 1 : { 1300, 1000 } } , { 3 : { 1300, 1000 } } }

因为我传递一个对象作为标识,所以我相信每个组都会更新同一个对象。因为lambda不能传递到 reduction 方法,有没有办法解决这个问题?

eqqqjvef

eqqqjvef1#

你可以使用 static 返回新示例的合并函数:

public static MyObject merge(MyObject one,MyObject two) {
    MyObject merged = new MyObject ();
    merged.setValue1(one.getValue1()+two.getValue1());
    merged.setValue2(one.getValue2()+two.getValue2());
    return merged;
}

您必须删除现有的非静态 merge 方法,以便 static 由编译器代替方法引用选择的方法。
这种方式, MyObject::merge 将产生一个新的 MyObject 每次都是示例。
如果不想删除现有方法,仍然可以添加 static 方法,如果将方法引用替换为以下lambda表达式:

(o1,o2)->MyObject.merge(o1,o2)

不添加 static 方法,可以替换 MyObject::merge 具有以下lambda表达式的方法引用:

(o1,o2)-> new MyObject().merge(o1).merge(o2)

相关问题