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

使用Java 8 Streams API按两个字段分组并返回更新后的集合

解决Java 8 Stream按部门+薪资分组并筛选多记录分组的问题

要实现按dept和salary联合分组,并只保留分组内记录数大于1的所有员工,核心是先构造复合分组键,再通过Stream完成分组、过滤、扁平化处理。

1. 确认Employee类实现

假设你的Employee类已实现如下(包含字段、构造器、Getter/Setter):

public class Employee {
    private String name;
    private String dept;
    private int age;
    private double salary;

    public Employee(String name, String dept, int age, double salary) {
        this.name = name;
        this.dept = dept;
        this.age = age;
        this.salary = salary;
    }

    // Getter和Setter方法
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getDept() { return dept; }
    public void setDept(String dept) { this.dept = dept; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }

    // 重写toString方便调试
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", dept='" + dept + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
}

2. Stream核心实现逻辑

用AbstractMap.SimpleEntry作为复合分组键(兼容Java 8),完成分组、过滤、扁平化流程:

import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class EmployeeFilter {
    public static List<Employee> getEmployeesFromLargeGroups(List<Employee> employeeList) {
        // 1. 按dept+salary联合分组
        Map<Map.Entry<String, Double>, List<Employee>> groupedByDeptAndSalary = employeeList.stream()
                .collect(Collectors.groupingBy(emp -> 
                        new AbstractMap.SimpleEntry<>(emp.getDept(), emp.getSalary())));

        // 2. 筛选分组大小>1的集合,再扁平化为单个员工列表
        return groupedByDeptAndSalary.values().stream()
                .filter(group -> group.size() > 1)
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }

    // 测试示例
    public static void main(String[] args) {
        List<Employee> employees = List.of(
                new Employee("Alice", "HR", 25, 5000.0),
                new Employee("Bob", "HR", 30, 5000.0), // 和Alice同部门同薪资,保留
                new Employee("Charlie", "Engineering", 35, 8000.0),
                new Employee("David", "Engineering", 28, 7500.0), // 单独分组,排除
                new Employee("Eve", "Engineering", 32, 8000.0), // 和Charlie同部门同薪资,保留
                new Employee("Frank", "Finance", 40, 9000.0) // 单独分组,排除
        );

        List<Employee> result = getEmployeesFromLargeGroups(employees);
        result.forEach(System.out::println);
    }
}

3. 代码说明

  • 复合分组键:AbstractMap.SimpleEntry已实现equals()和hashCode(),可直接作为Map的key,将dept和salary绑定为唯一分组标识。
  • 分组过滤:分组后仅保留元素数量大于1的分组,排除单条记录的分组。
  • 扁平化处理:通过flatMap()将多个符合条件的分组列表合并为一个员工列表。

4. Java 16+优化方案

如果使用Java 16及以上,可改用**记录类(Record)**替代SimpleEntry,代码可读性更强:

// 定义记录类作为分组键
public record DeptSalaryGroup(String dept, double salary) {}

// 修改分组逻辑
Map<DeptSalaryGroup, List<Employee>> grouped = employeeList.stream()
        .collect(Collectors.groupingBy(emp -> new DeptSalaryGroup(emp.getDept(), emp.getSalary())));

运行测试代码后,输出会保留Alice、Bob、Charlie、Eve,排除David和Frank,完全符合需求。

内容的提问来源于stack exchange,提问作者Anil Nivargi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 18:22:44