You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 21:15:04