java - 为什么按 Id 对对象列表进行分组仅在该函数中第一次调用时有效?

标签 java arraylist group-by sum

我想将对象列表(来自数据库)按其元素进行分组,这与以下简化代码配合使用效果良好:

List<MyClass> sqlResultList;
List<MyClass> resultList;

public void applyMerge() {

    Map<Integer, List<MyClass>> map = 
            sqlResultList.stream().collect(Collectors.groupingBy(MyClass::getIdItem));

    resultList = new ArrayList<>();
    for (Integer IdItem : map.keySet()) {

        List<MyClass> tmp = map.get(IdItem);

        if (tmp.size() > 0) {  

            MyClass head = tmp.get(0); // seems to create just a reference

        for (int i = 1; i < tmp.size(); i++) {

                MyClass obj = tmp.get(i);
                head.setMinutes(head.getMinutes() + obj.getMinutes());

            }

            resultList.add(head);

        } 
    }
}

我遇到的唯一问题是,如果我记得 applyMerge() 函数,它会将所有值添加到之前的总和值之上。我以为对象MyClass head只是一个临时对象,但它似乎是一个引用tmpmap

有什么提示我的误解是什么吗?

ps:我可以从数据库更新sqlResultList,但我想避免这种情况,因为数据本身没有改变。

最佳答案

您的 head 对象是对原始列表中的对象的引用。它不是副本,因此您对该对象所做的任何修改也将被对该对象的任何其他引用看到。

您将需要克隆该对象:

MyClass head = tmp.get(0).clone();

克隆的方法各不相同,但典型的方法是重写 Object#clone() 方法。在此方法中,您将创建 MyClass 的新实例,然后复制所需的所有属性。例如:

public class MyClass {
    private int minutes;

    public MyClass clone() {
        MyClass clonedInstance = new MyClass();
        clonedInstance.setMinutes(getMinutes());
        return clonedInstance;
    }

    public int getMinutes() {
        return this.minutes;
    }

    public void setMinutes(int minutes) {
        this.minutes = minutes;
    }
}

如果您有其他属性,那么您将需要确保您也了解任何必要的深度克隆。例如,如果您有一个可变类型的属性(例如 List),那么您可能需要克隆该属性,等等。

许多标准 JDK 类型也提供了自己的 clone 方法,例如 ArrayList

关于java - 为什么按 Id 对对象列表进行分组仅在该函数中第一次调用时有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47562555/

相关文章:

java - 如何从 SubscriableChannel 构建 KStream

java - com.android.volley.NoConnectionError : java.net.ConnectException:连接被拒绝

java - 用 C++ 编写的句法和语义代码完成框架

java - 如何在java控制台中以表格形式显示arraylist

SQL查询分组参数最大值

java - 在 UCanAccess 中通过 DDL 创建的表无法在 Access 本身中打开

java - 字符串列表获取一个没有循环开始的项目

java - ArrayList 包含未检测到它应该包含的内容

mysql - 多项赛事积分榜

sql - 在 JOIN 之后选择 DISTINCT 值