如何解决Java Streams中出现的IllegalStateException: Duplicate key异常?
如何解决Java Streams中出现的IllegalStateException: Duplicate key异常?
嘿,我之前也踩过这个一模一样的坑!你看你这段代码:
List<String> list = List.of("a", "b", "a"); Map<String, Integer> map = list.stream() .collect(Collectors.toMap(s -> s, String::length));
运行起来直接就炸出java.lang.IllegalStateException: Duplicate key a (attempted merging values 1 and 1)的异常,对吧?
这事儿说穿了也简单:Collectors.toMap()的默认逻辑特别“轴”——当流里出现重复的键时,它不知道该留哪个对应的值,索性直接抛出异常甩锅给你😅
那怎么搞定它?给你两个实用方案,看你实际需求选:
1. 给toMap加个合并规则
toMap其实有个重载方法,第三个参数就是专门处理重复键的合并函数,你得明确告诉它:碰到重复键时,是留旧值、用新值覆盖,还是把两个值合并起来。
比如你想保留第一个出现的value,就这么写:
List<String> list = List.of("a", "b", "a"); Map<String, Integer> map = list.stream() .collect(Collectors.toMap( s -> s, String::length, (existingValue, newValue) -> existingValue // 保留已有的旧值 ));
要是想让新值覆盖旧值,把合并函数改成(existingValue, newValue) -> newValue就行。如果你的value是可计算的(比如两个数字相加),还能这么玩:(existing, newVal) -> existing + newVal,直接把两个值合并成一个。
2. 用groupingBy来分组处理
如果你其实是想统计每个键对应的元素情况(比如统计每个字符串出现的次数),那用Collectors.groupingBy会更顺手,它天生就支持重复键的分组:
比如统计每个字符串的出现次数:
List<String> list = List.of("a", "b", "a"); Map<String, Long> countMap = list.stream() .collect(Collectors.groupingBy( s -> s, Collectors.counting() // 统计每个组的元素个数 ));
要是你想保留每个键对应的所有value列表,也能这么写:
Map<String, List<Integer>> valueListMap = list.stream() .collect(Collectors.groupingBy( s -> s, Collectors.mapping(String::length, Collectors.toList()) ));
这样每个键对应的就是所有出现过的value的列表,完全不会有重复键的烦恼。
说白了就是得给Java一个明确的指令:碰到重复键别瞎慌,按我说的来处理就行~
内容来源于stack exchange
相关产品推荐
相关产品推荐

