我想将对象列表(来自数据库)按其元素进行分组,这与以下简化代码配合使用效果良好:
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
只是一个临时对象,但它似乎是一个引用tmp
和map
。
有什么提示我的误解是什么吗?
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/