如何在运行时根据属性值动态将Employee List拆分为List集合
按name、sal、joinDate动态分组Employee列表的方案
要实现不硬编码属性值、按name/sal/joinDate组合动态分组的需求,核心是利用Java Stream的Collectors.groupingBy,通过自定义分组键来匹配属性组合——只要两个Employee的这三个属性完全相等,就会被分到同一组。
第一步:完善Employee类
原Employee类缺少属性getter,必须添加才能在stream中获取分组所需的属性值:
import java.math.BigDecimal; import java.util.Date; public class Employee { private String name; private long id; private BigDecimal sal; private Date joinDate; public Employee(String name, long id, BigDecimal sal, Date date) { super(); this.name = name; this.id = id; this.sal = sal; this.joinDate = date; } // 添加分组所需的getter public String getName() { return name; } public BigDecimal getSal() { return sal; } public Date getJoinDate() { return joinDate; } // 可选:重写toString方便查看结果 @Override public String toString() { return "Employee{name='" + name + "', id=" + id + ", sal=" + sal + ", joinDate=" + joinDate + '}'; } }
方案一:自定义分组键类(兼容Java 8+)
创建一个包含三个分组属性的GroupKey类,重写equals和hashCode——这是分组的核心依据,确保相同属性组合的键会被视为相等:
import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; import java.util.ArrayList; import java.text.SimpleDateFormat; import java.util.stream.Collectors; class GroupKey { private final String name; private final BigDecimal sal; private final Date joinDate; public GroupKey(String name, BigDecimal sal, Date joinDate) { this.name = name; this.sal = sal; this.joinDate = joinDate; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GroupKey groupKey = (GroupKey) o; return name.equals(groupKey.name) && sal.equals(groupKey.sal) && joinDate.equals(groupKey.joinDate); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + sal.hashCode(); result = 31 * result + joinDate.hashCode(); return result; } } public class EmployeeGroupingDemo { public static void main(String[] args) throws Exception { List<Employee> employeeList = new ArrayList<>(); // 注意用yyyy表示年,避免YYYY(周年)的解析问题 SimpleDateFormat format = new SimpleDateFormat("MMddyyyy"); employeeList.add(new Employee("Mike", 1000, BigDecimal.valueOf(200), format.parse("08122022"))); employeeList.add(new Employee("David", 1001, BigDecimal.valueOf(100), format.parse("08112022"))); employeeList.add(new Employee("Mike", 1002, BigDecimal.valueOf(200), format.parse("08122022"))); employeeList.add(new Employee("David", 1003, BigDecimal.valueOf(100), format.parse("08112022"))); employeeList.add(new Employee("David", 1003, BigDecimal.valueOf(200), format.parse("08112022"))); employeeList.add(new Employee("David", 1003, BigDecimal.valueOf(200), format.parse("08122022"))); // 核心分组逻辑:用GroupKey作为分组依据 Map<GroupKey, List<Employee>> groupedMap = employeeList.stream() .collect(Collectors.groupingBy(emp -> new GroupKey(emp.getName(), emp.getSal(), emp.getJoinDate()))); // 将Map的value转换为需求的List<List<Employee>> List<List<Employee>> result = new ArrayList<>(groupedMap.values()); // 打印验证分组结果 int groupNum = 1; for (List<Employee> group : result) { System.out.println("第" + groupNum + "组:"); group.forEach(System.out::println); groupNum++; } } }
方案二:用Java 16+ Record简化代码
Java 16引入的Record会自动生成equals、hashCode和toString,可以大幅简化分组键的编写:
import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; import java.util.ArrayList; import java.text.SimpleDateFormat; import java.util.stream.Collectors; // Record自动实现equals和hashCode,直接作为分组键 record GroupKey(String name, BigDecimal sal, Date joinDate) {} public class EmployeeGroupingDemo { public static void main(String[] args) throws Exception { List<Employee> employeeList = new ArrayList<>(); SimpleDateFormat format = new SimpleDateFormat("MMddyyyy"); employeeList.add(new Employee("Mike", 1000, BigDecimal.valueOf(200), format.parse("08122022"))); employeeList.add(new Employee("David", 1001, BigDecimal.valueOf(100), format.parse("08112022"))); employeeList.add(new Employee("Mike", 1002, BigDecimal.valueOf(200), format.parse("08122022"))); employeeList.add(new Employee("David", 1003, BigDecimal.valueOf(100), format.parse("08112022"))); employeeList.add(new Employee("David", 1003, BigDecimal.valueOf(200), format.parse("08112022"))); employeeList.add(new Employee("David", 1003, BigDecimal.valueOf(200), format.parse("08122022"))); // 分组逻辑更简洁 Map<GroupKey, List<Employee>> groupedMap = employeeList.stream() .collect(Collectors.groupingBy(emp -> new GroupKey(emp.getName(), emp.getSal(), emp.getJoinDate()))); List<List<Employee>> result = new ArrayList<>(groupedMap.values()); // 打印结果 int groupNum = 1; for (List<Employee> group : result) { System.out.println("第" + groupNum + "组:"); group.forEach(System.out::println); groupNum++; } } }
关键说明
Collectors.groupingBy会根据提供的键提取器,自动将属性组合相同的Employee分到同一组,无需硬编码任何属性值。BigDecimal和Date都正确实现了equals和hashCode,可以直接作为分组键的属性。- 运行上述代码,示例中的6个Employee会被分成4组(与你提到的3组可能存在示例数据描述误差),完全符合动态分组的需求。
内容的提问来源于stack exchange,提问作者chaitu
相关产品推荐
相关产品推荐

