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

Java 8使用Stream转Map遇重复值抛出IllegalStateException问题

解决Java Stream转换Map时的Duplicate Key异常

当你用Java Stream将包含重复键的列表转换为Map时,默认的Collectors.toMap()方法会直接抛出IllegalStateException: Duplicate key异常——这正是你遇到的问题。咱们先看你的示例代码和对应的错误输出:

错误示例代码

List<Employee> empList = new ArrayList<Employee>();
Employee e1 = new Employee(1,"aaaa","mgr",100666.99);
Employee e2 = new Employee(2,"bbbb","lead",90675.99);
Employee e3 = new Employee(3,"cccc","dev",77555.99);
Employee e4 = new Employee(4,"dddd","qe",63546.99);
Employee e5 = new Employee(5,"eeee","lead",90675.99);
Employee e6 = new Employee(6,"ffff","lead",90675.99);
Employee e7 = new Employee(7,"gggg","dev",90675.99);
Employee e8 = new Employee(8,"hhhh","qe",90675.99);
empList.add(e1);
empList.add(e2);
empList.add(e3);
empList.add(e4);
empList.add(e5);
empList.add(e6);
empList.add(e7);
empList.add(e8);

List<Department> deptList = new ArrayList<Department>();
Department d1 = new Department(1, "IT", 10);
Department d2 = new Department(2, "Sales", 20);
Department d3 = new Department(3, "HR", 30);
Department d4 = new Department(4, "Support", 40);
deptList.add(d1);
deptList.add(d2);
deptList.add(d3);
deptList.add(d4);

System.out.println("\n\n List of Leads Names :");
List<String> empNames = empList.stream().filter(emp -> "lead".equals(emp.job)).map(Employee::getName).collect(Collectors.toList());
empNames.forEach(System.out::println);

// 这里会抛出Duplicate Key异常
Map<String,Double> jobSalMap = empList.stream().filter(emp -> "lead".equals(emp.job)).collect(Collectors.toMap(emp->emp.job,emp->emp.sal));
jobSalMap.forEach(new BiConsumer<String,Double>(){
    @Override
    public void accept(String arg0, Double arg1) {
        System.out.println(arg0 + " " + arg1);
    }
});

double sumOfLeadSal = empList.stream().filter(emp -> "lead".equals(emp.job)).mapToDouble(Employee::getSal).sum();
System.out.println(sumOfLeadSal);

错误输出

List of Leads Names :
bbbb
eeee
ffff
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 90675.99
at java.util.stream.Collectors.lambda$throwingMerger$0(Unknown Source)
at java.util.HashMap.merge(Unknown Source)
at java.util.stream.Collectors.lambda$toMap$58(Unknown Source)
at java.util.stream.ReduceOps$3ReducingSink.accept(Unknown Source)
at java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.collect(Unknown Source)
at com.zzar.practice.TestEmployee.main(TestEmployee.java:59)

解决方案:添加合并函数

问题出在Collectors.toMap()的默认行为——当检测到重复键时,它会使用一个默认的"抛出异常"合并策略。要解决这个问题,只需要在toMap()方法中传入第三个参数:合并函数,用来定义遇到重复键时如何处理对应的value。

比如,如果你想保留最后一个遇到的value:

Map<String,Double> jobSalMap = empList.stream()
    .filter(emp -> "lead".equals(emp.job))
    .collect(Collectors.toMap(
        emp -> emp.job,       // key提取函数
        emp -> emp.sal,       // value提取函数
        (oldVal, newVal) -> newVal  // 合并策略:保留新值
    ));

如果你想把相同key的所有薪资求和:

Map<String,Double> jobSalMap = empList.stream()
    .filter(emp -> "lead".equals(emp.job))
    .collect(Collectors.toMap(
        emp -> emp.job,
        emp -> emp.sal,
        (oldVal, newVal) -> oldVal + newVal  // 合并策略:薪资累加
    ));

合并函数的逻辑完全可以根据你的业务需求自定义——比如把多个value收集到一个List里:

Map<String,List<Double>> jobSalMap = empList.stream()
    .filter(emp -> "lead".equals(emp.job))
    .collect(Collectors.toMap(
        emp -> emp.job,
        emp -> new ArrayList<>(Collections.singletonList(emp.sal)),
        (oldList, newList) -> {
            oldList.addAll(newList);
            return oldList;
        }
    ));

这样修改后,代码就不会再抛出重复键的异常,而是按照你定义的规则处理重复的键值对。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:28:53