Java8中如何按多个公共属性对列表中的对象进行GroupBy分组
Java8 多属性分组实现方案
快速实现(无需新增类)
Collectors.groupingBy的分类函数支持返回任意对象作为分组键,利用List的 equals 规则会匹配所有元素的特性,可以直接把需要分组的多个属性封装为List作为键:
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; // 多属性分组代码 Map<List<Object>, List<Cause>> result = request.getList(criteria) .stream() .map(p -> parsin.createDto(p)) .collect(Collectors.groupingBy(cause -> Arrays.asList( cause.getId(), cause.getCreationDate(), cause.getOrigin(), cause.getDestination() )));
注意:该方案的优势是实现成本低,不需要额外编写代码;缺点是Map的键为
List<Object>类型,类型不安全、语义不清晰,仅适合临时快速开发使用。
规范实现(类型安全)
如果需要语义清晰、类型安全的分组键,可以自定义分组键类,重写equals和hashCode方法:
步骤1:定义分组键类
可以把键类作为静态内部类放在Cause中:
import java.util.Objects; public class Cause extends GeneralDomain { // 原有属性、getter、setter省略 public static class GroupKey { private final Long id; private final Date creationDate; private final Part origin; private final Part destination; public GroupKey(Cause cause) { this.id = cause.getId(); this.creationDate = cause.getCreationDate(); this.origin = cause.getOrigin(); this.destination = cause.getDestination(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GroupKey groupKey = (GroupKey) o; return Objects.equals(id, groupKey.id) && Objects.equals(creationDate, groupKey.creationDate) && Objects.equals(origin, groupKey.origin) && Objects.equals(destination, groupKey.destination); } @Override public int hashCode() { return Objects.hash(id, creationDate, origin, destination); } } }
步骤2:使用自定义键分组
Map<Cause.GroupKey, List<Cause>> result = request.getList(criteria) .stream() .map(p -> parsin.createDto(p)) .collect(Collectors.groupingBy(Cause.GroupKey::new));
Java16+ 简化实现
如果使用Java16及以上版本,可以用record直接定义不可变的分组键,无需手动编写equals和hashCode:
// 定义record作为分组键,自动生成构造、equals、hashCode方法 public record CauseGroupKey(Long id, Date creationDate, Part origin, Part destination) {}
分组代码:
Map<CauseGroupKey, List<Cause>> result = request.getList(criteria) .stream() .map(p -> parsin.createDto(p)) .collect(Collectors.groupingBy(cause -> new CauseGroupKey( cause.getId(), cause.getCreationDate(), cause.getOrigin(), cause.getDestination() )));
注意事项
所有参与分组的属性对应的类(示例中的Part、Date)必须已经正确重写equals和hashCode方法,否则会出现相同属性值的对象被分到不同组的问题。
内容的提问来源于stack exchange,提问作者Oscar Navarrete
相关产品推荐
相关产品推荐

