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

Java 8 Stream如何将List<Employee>转为Map<Integer,Set<Set<String>>>

Java 8 Stream实现员工手机号按项目分组并分区

类定义

class Employee{
    private Integer employeeId;
    private Integer projectId;
    private String mobileNumbers;

    // 需配套提供getter方法:getProjectId()、getMobileNumbers()
}

需求

将员工列表转换为Map<Integer, Set<Set<String>>>:

  • 键:员工所属的projectId
  • 值:该项目下所有员工的手机号集合,需先将逗号分隔的多手机号拆分为单个元素,再按每100个一组分区,最终存储为嵌套集合Set<Set<String>>

当前问题

现有代码仅能实现Map<Integer, Set<String>>,存在两个核心缺陷:

  1. 无法将mobileNumbers字段中逗号分隔的多手机号拆分为Set中的单个元素
  2. 无法实现每100个手机号一组的分区逻辑

示例

输入

Employee[employeeId=1,projectId=1,mobileNumbers="1111,2222"]
Employee[employeeId=2,projectId=1,mobileNumbers="33333"]
Employee[employeeId=3,projectId=2,mobileNumbers="44444,5555"]

预期输出

{1=[["1111","2222","33333"]], 2=[["44444","5555"]]}

现有代码

Map<Integer,Set<String>> result2=employeeList.stream()
         .collect(
          Collectors.groupingBy(Employee::getProjectId,
              Collectors.mapping(Employee::getMobileNumbers, Collectors.toSet()))
      );

解决方案

通过flatMap拆分手机号,结合collectingAndThen实现分区逻辑,完整代码如下:

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class EmployeeProcessor {
    public static void main(String[] args) {
        List<Employee> employeeList = Arrays.asList(
                new Employee(1, 1, "1111,2222"),
                new Employee(2, 1, "33333"),
                new Employee(3, 2, "44444,5555")
        );

        Map<Integer, Set<Set<String>>> result = employeeList.stream()
                // 拆分逗号分隔的手机号,过滤空串与空白值,转换为单手机号流
                .flatMap(emp -> {
                    if (emp.getMobileNumbers() == null || emp.getMobileNumbers().trim().isEmpty()) {
                        return Stream.empty();
                    }
                    return Arrays.stream(emp.getMobileNumbers().split(","))
                            .map(String::trim)
                            .filter(s -> !s.isEmpty());
                })
                // 按projectId分组,先收集所有手机号去重,再执行分区
                .collect(Collectors.groupingBy(Employee::getProjectId,
                        Collectors.collectingAndThen(Collectors.toSet(), phoneSet -> {
                            Set<Set<String>> partitionedSets = new HashSet<>();
                            List<String> phoneList = new ArrayList<>(phoneSet);
                            // 每100个一组拆分集合
                            for (int i = 0; i < phoneList.size(); i += 100) {
                                int endIndex = Math.min(i + 100, phoneList.size());
                                partitionedSets.add(new HashSet<>(phoneList.subList(i, endIndex)));
                            }
                            return partitionedSets;
                        })));

        System.out.println(result);
    }
}

// 补全Employee类的构造方法与getter
class Employee {
    private Integer employeeId;
    private Integer projectId;
    private String mobileNumbers;

    public Employee(Integer employeeId, Integer projectId, String mobileNumbers) {
        this.employeeId = employeeId;
        this.projectId = projectId;
        this.mobileNumbers = mobileNumbers;
    }

    public Integer getProjectId() {
        return projectId;
    }

    public String getMobileNumbers() {
        return mobileNumbers;
    }
}

代码说明

  1. flatMap处理拆分:将每个员工的mobileNumbers按逗号分割,过滤空值与空白手机号,转换为单个手机号的流,解决多手机号拆分问题。
  2. 分组后分区:通过collectingAndThen先将同一项目下的所有手机号收集到Set中去重,再将该集合按每100个元素一组拆分,生成嵌套的Set<Set<String>>。
  3. 空值防护:增加了对mobileNumbers为空的判断,避免空指针异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 19:45:10