Java8中List转Map报错“java.lang.IllegalStateException: Duplicate key”

文章讲述了在Java编程中遇到的Duplicatekey错误,源于数据库主键冲突。作者在处理文件列表时,由于Map的key唯一性导致错误。通过分析错误信息和源码,发现使用`toMap`的重载方法解决了这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

排查思路

  1. 从报错的关键字中可以大致判断是是key冲突,Duplicate key在数据库的主键冲突错误中经常遇到,个人的思维惯性就联想到了数据库,从这个方向去排查,无果。
  2. 抓耳挠腮之下,分析如下错误信息
java.lang.IllegalStateException: Duplicate key image(id=1,name='晓明')
  at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
  at java.util.HashMap.merge(HashMap.java:1253)
  at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)

这里是当时的问题代码,本意是想把查出来的文件list再以文件fileId作为Map的key转换成map,结果库里有两个一样的文件ID就导致了错误的发生,因为map的key是唯一的。

Map<String, ImageFile> oldImageFileMap = 
       list(new LambdaQueryWrapper<ImageFile>()
       .eq(ImageFile::getOrderNo, orderNo)
       .eq(ImageFile::getDeleteFlag, 0))
       .stream().collect(Collectors.toMap(ImageFile::getOriginalFileId, Function.identity()));

以下是源码片段

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper) {
        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}
public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
    }
private static <T> BinaryOperator<T> throwingMerger {
    return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
}

解决方案:
用集合转map的另外的重载方法二
在这里插入图片描述
修改后的代码

        Map<String, ImageFile> oldImageFileMap = list(new LambdaQueryWrapper<ImageFile>()
                .eq(ImageFile::getOrderNo, orderNo)
                .eq(ImageFile::getDeleteFlag, 0))
                .stream().collect(Collectors.toMap(ImageFile::getOriginalFileId, Function.identity(),(v1,v2)->v2));
<think>好的,我现在需要解决用户遇到的Java中的IllegalStateException,具体是Duplicate key错误。用户提到在使用流处理中的Collectors.toMap时出现这个问题。根据引用中的信息,当流中的元素有重复的键时,就会抛出这个异常。 首先,我得回忆一下Collectors.toMap的用法。默认情况下,toMap方法不允许键重复,如果遇到重复的键,就会抛出异常。用户提供的示例代码中,列表里有重复的字符串,比如"apple"出现了两次,导致作为键时重复,从而触发异常。 接下来,我需要找出解决方案。常见的解决方法有几个:1)处理键重复的情况,合并或覆盖值;2)使用其他数据结构来避免键冲突,比如分组;3)在收集之前确保键的唯一性。 根据引用中的例子,用户可能是在使用toMap时没有处理重复键的情况。所以,解决方法应该在收集时提供一个合并函数,告诉Java当键重复时如何处理。例如,可以选择保留旧值或新值,或者合并两者。 另外,用户提到的键是0.1,这可能意味着键是Double类型。需要注意浮点数作为键时可能存在的精度问题,但这里可能只是示例中的具体值。不过,这提醒我要确保键的正确生成方式,避免因为计算错误导致重复键。 然后,我应该详细说明每个解决方法的步骤,比如修改Collectors.toMap的调用,添加合并函数。例如,使用lambda表达式 (oldVal, newVal) -> oldVal 来保留第一个出现的值,或者选择覆盖为新的值。 此外,还可以提到使用groupingBy来将相同键的值收集到列表中,这样就不会抛出异常,而是将值分组处理。这也是一种替代方法。 最后,需要提醒用户在生成键时确保唯一性,或者在数据源处理阶段去重,避免重复键的出现。这可以作为预防措施。 总结起来,解决方案包括:添加合并函数处理重复键、使用分组收集器、或在收集前确保键唯一。需要逐步解释每个方法的实现方式,并给出示例代码,帮助用户理解和应用。</think>### Java.lang.IllegalStateException: Duplicate key 解决方案 该异常通常在使用Java流(Stream)的`Collectors.toMap()`方法时发生,原因是将流元素换为Map时出现重复键。以下是具体原因与解决方案: --- #### **原因分析** 1. **键生成规则冲突** 流中多个元素的键(通过`Function`生成)重复,例如: ```java List<String> list = Arrays.asList("apple", "banana", "apple"); Map<String, Integer> map = list.stream() .collect(Collectors.toMap(key -> key, value -> value.length())); ``` 此处两个"apple"会生成重复键,导致异常[^2]。 2. **数值精度问题(如0.1)** 若键为浮点数(如`0.1`),需注意浮点数的精度问题可能导致意外重复(例如`0.1 + 0.2 != 0.3`)。但更常见的是业务逻辑直接生成的键重复。 --- #### **解决方案** ##### **方法1:使用合并函数处理重复键** 在`Collectors.toMap()`中增加第三个参数(合并函数),定义重复键的处理逻辑: ```java Map<String, Integer> map = list.stream() .collect(Collectors.toMap( key -> key, // 键生成规则 value -> value.length(), // 值生成规则 (oldVal, newVal) -> oldVal // 合并规则:保留旧值(或选择newVal覆盖) )); ``` - 选择`oldVal`保留首次出现的值,选择`newVal`覆盖为最新值[^1]。 ##### **方法2:使用分组收集器** 若需要保留所有重复键对应的值,改用`Collectors.groupingBy()`: ```java Map<String, List<Integer>> groupedMap = list.stream() .collect(Collectors.groupingBy( key -> key, Collectors.mapping(value -> value.length(), Collectors.toList()) )); ``` ##### **方法3:提前过滤重复键** 在收集前确保键唯一: ```java Map<String, Integer> map = list.stream() .distinct() // 去重 .collect(Collectors.toMap(key -> key, value -> value.length())); ``` --- #### **预防建议** 1. **检查键生成逻辑** 确保键生成规则不会产生重复,例如通过组合多个字段生成唯一键: ```java .collect(Collectors.toMap( item -> item.getId() + "_" + item.getName(), // 复合键 item -> item )); ``` 2. **数值键需注意精度** 使用`BigDecimal`代替`Double`避免浮点数精度问题: ```java .collect(Collectors.toMap( item -> new BigDecimal(item.getKeyValue()), item -> item )); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值