记录一个最近遇到的问题,当需要对一个List的数据分组时,通常我们会使用stream的grouping by方法,它通常会将List按某个字段或属性值分组,然后返回一个Map<String, List>结构类型。
但有些时候你需要对多个字段分组,这时候有两种解决办法,第一种可以继续使用grouping by方法,对两个字段进行拼接,例如:
Map<String, List<BillReceiptQueryDto>> map = temp.stream()
.collect(Collectors.groupingBy(o -> o.getCustomerId() + "##" + o.getMonthYear()));
但有时候你就是不想用这种看起来有点简陋的写法,这就回到了标题,将实体类对象设置为HashMap的key。
我创建了一个实体类,其中包含3个我想要分组的字段,因为我不想##连接3个字段看起来太丑了。很容易想象,如果只有get set方法那大概率在你put进map里之后,下次遇到3个字段完全相同的实体类还是会当作新key被put进去而不是加入旧的组里。
public class ReceiptUpdateEntity {
private Date billMonth;
private String customerId;
private String productId;
public Date getBillMonth() {
return billMonth;
}
public void setBillMonth(Date billMonth) {
this.billMonth = billMonth;
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
}
如下我创建了一个简单的测试方法,将3个值都赋值相同的两个对象先后作为key put、containsKey,校验后发现输出false,和预料中一样HashMap并没有判断两个对象相同。解决办法就是重写这个类的equals和hashCode方法,用idea自动生成就行,只有这样才能让HashMap在识别的时候判断这两个对象是相同的。
Date temp = DateUtil.convert("2023-10-01 00:00:00", DateUtil.format1);
Date temp2 = DateUtil.convert("2023-10-01 00:00:00", DateUtil.format1);
Map<ReceiptUpdateEntity, List<CustomerProductTj>> collect = new HashMap<>();
ReceiptUpdateEntity updateEntity = new ReceiptUpdateEntity();
String customerId = "123456789";
String productId = "123456798";
updateEntity.setBillMonth(temp);
updateEntity.setCustomerId(customerId);
updateEntity.setProductId(productId);
collect.put(updateEntity, null);
ReceiptUpdateEntity updateEntity2 = new ReceiptUpdateEntity();
String customerId2 = "123456789";
String productId2 = "123456798";
updateEntity2.setBillMonth(temp2);
updateEntity2.setCustomerId(customerId2);
updateEntity2.setProductId(productId2);
System.out.println(collect.containsKey(updateEntity2));
ReceiptUpdateEntity updateEntity3 = new ReceiptUpdateEntity();
String customerId3 = "123456789";
String productId3 = "";
updateEntity3.setBillMonth(temp2);
updateEntity3.setCustomerId(customerId3);
updateEntity3.setProductId(productId3);
System.out.println(collect.containsKey(updateEntity3));
// 可以在Map里使用对象作为key 但需要重写这个对象类的equals和hashcode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ReceiptUpdateEntity that = (ReceiptUpdateEntity) o;
return billMonth.equals(that.billMonth) && customerId.equals(that.customerId) && productId.equals(that.productId);
}
@Override
public int hashCode() {
return Objects.hash(billMonth, customerId, productId);
}
@Override
public String toString() {
return "ReceiptUpdateEntity{" +
"billMonth=" + billMonth +
", customerId='" + customerId + '\'' +
", productId='" + productId + '\'' +
'}';
}