java - 在 Java 8 中,如果 map 具有重复值,则会出现重复值异常
问题描述
IllegalStateException: Duplicate key
如果列表中有重复值,并且我们尝试使用 java 流从列表中提取映射,则代码正在生成一个。如果我们在 collect 方法中定义合并函数,那么问题就解决了。
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);
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)
解决方案
第一个解决方案:您需要按职位知道固定工资 - 没有总和。
您可以将 toMap 函数与合并运算符一起使用:
Map<String, Double> mapByJob = empList.stream()
.collect(Collectors.toMap(Employee::getJob, Employee::getSal, (sal1, sal2) -> sal1));
mapByJob .forEach((job, sal) -> System.out.println(job + " -> " + sal));
这将打印输出:
铅-> 90675.99
笔记:
- Employee::getJob 与您的 emp->emp.job “等效”
- 但由于工资不是恒定的,我不会使用这个解决方案(见第二个解决方案)。
第二种解决方案:您需要按职位知道薪水 - 用总和
通过按职位汇总工资,它就变成了非常方便的信息:
Map<String, Double> mapByJob = empList.stream()
.collect(Collectors.toMap(Employee::getJob, Employee::getSal, (sal1, sal2) -> sal1+sal2));
mapByJob .forEach((job, sal) -> System.out.println(job + " -> " + sal));
结果如下:
qe -> 154222.98
开发-> 168231.98
经理-> 100666.99
铅-> 272027.97000000003
Java 文档:收集器
推荐阅读
- java - Selenium Webdriver 问题无法打开谷歌浏览器
- python - Matplotlib - 对齐网格
- python - 如何使用 django 过滤器或以某种方式获取“最近”元素
- java - 来自 Firebase 的数据未显示在 RecyclerView 中
- php - 如果表单验证失败,则使用自定义请求类(laravel 5.8)通过输入重定向回来
- python - Flask 会话数据可以被用户(威胁参与者)更改吗?
- android - Android Studio 中的 Gradle 依赖项
- three.js - 我可以将 THREE.js 材料放在 gltf 模型上吗?
- git - 如何在 Mac 上为 Fork 配置 SSH 私钥?
- c++ - 合并排序和合并 C++