详细解决java中的Collectors.toMap引起的java.lang.IllegalStateException: Duplicate key xxx 的错误

1. 复现错误


今天,测试在禅道上给我指出一个正式环境bug,如下图所示:

在这里插入图片描述

java.lang.IllegalStateException: Duplicate key 2

2. 分析错误


根据java.lang.IllegalStateException: Duplicate key 2可知,这是java抛出的存在2个重复键的错误。

如果想要弄清楚错误原因,通过如下几个步骤分析:

  1. 首先,看到这个错误信息,先在本地使用postman测试这个接口,如下图所示:

在这里插入图片描述

由于涉及到公司的安全,不能把接口展示出来。

由上图可知,本地环境没有问题。

  1. 查看正式环境的日志,如下图所示:

在这里插入图片描述

由错误的第2行可知,这是stream.Collectors引起出的错误。

继续往下看,找到红框处,这是项目代码错误抛出的的位置。

于是,查看线上的代码如下所示:

xxxRepository.list(new xxxQuery().setXxx(xxxId))
                .stream()
                .collect(Collectors.toMap(xxxEntity::getName, xxxEntity::getId));

由于保密机制,把实际名称,用xxx替换了。

xxxEntity::getName代码猜想:可能是由于数据库存在两个相同的名字,在转化成Map时就会存在相同的Key,从而导致hash异常,如下代码所示:

@Data
@NoArgsConstructor
public class Student {
  private BigDecimal score;
  private String name;
  private Integer id;
  private Integer age;

  @Override
  public String toString() {
    return JSON.toJSONString(this);
  }

  public Student(BigDecimal score, String name, Integer id, Integer age) {
    this.score = score;
    this.name = name;
    this.id = id;
    this.age = age;
  }

  public static void main(String[] args) {
    Student student1 = new Student(new BigDecimal(99.5), "陈希尔", 1, 12);
    Student student2 = new Student(new BigDecimal(88), "陈希尔", 2, 12);

    List<Student> list = new ArrayList();
    list.add(student1);
    list.add(student2);

    Map<String, Integer> collect =
        list.stream().collect(Collectors.toMap(Student::getName, Student::getId));
    Set<String> keys = collect.keySet();
    String sout = "key = %s, value = %s \n";
    keys.forEach(t -> System.out.format(sout, t, collect.get(t)));
  }
}

注意上述的示例代码,下文也是基于此示例代码修改。

输出结果如下图所示:

在这里插入图片描述

  1. 根据猜想到数据库中查询数据,如下所示:
select
    COUNT(`name`) as nameCount,
    `name`
from
    xxx_table
GROUP BY
    `name`
HAVING
    nameCount >= 2;

在这里插入图片描述

找到了问题的所在,原来是name重复了,导致这个错误。

在实际应用开发中,我们会常把一个List的查询数据集合转为一个Map,那么在这里的 list.stream().collect()其实就是做了这么一件事情,它是java8stream方式实现的它是以typekey,以entity对象为value构成Map

本错误中的type就是name,而map中的key值是不能重复的,重复会导致hash异常。

3. 解决问题


既然知道了问题的原因,我们可以用如下方式解决:

  1. 删除name重复记录

  2. 修改代码,保证即便有重复的值,也能转化成Map

我们只需要将这行代码:

 Map<String, Integer> collect =
        list.stream().collect(Collectors.toMap(Student::getName, Student::getId));

按如下方式修改即可:

 Map<String, Integer> collect =
        list.stream()
            .collect(
                Collectors.toMap(Student::getName, Student::getId, (entity1, entity2) -> entity1));

此代码等效于:

Map<String, Integer> collect =
        list.stream()
            .collect(
                Collectors.toMap(
                    Student::getName,
                    Student::getId,
                    new BinaryOperator<Integer>() {
                      @Override
                      public Integer apply(Integer entity1, Integer entity2) {
                        return entity1;
                      }
                    }));

修改完后,如下为测试结果:

在这里插入图片描述

4. 重要补充

 Map<String, Integer> collect =
        list.stream()
            .collect(
                Collectors.toMap(Student::getName, Student::getId, (entity1, entity2) -> entity1));

等效于:

Map<String, Integer> collect =
        list.stream()
            .collect(
                Collectors.toMap(
                    Student::getName,
                    Student::getId,
                    new BinaryOperator<Integer>() {
                      @Override
                      public Integer apply(Integer entity1, Integer entity2) {
                        return entity1;
                      }
                    }));

我们去看toMap的源代码就知道了,如下图所示:

在这里插入图片描述

它第三个参数就是函数式接口,因而,我们可以使用lamda表达式来简化代码。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
java.lang.IllegalStateException: Duplicate key异常是指在使用Java编程语言时,出现了重复键的异常。重复键的意思是在使用键值对的数据结构时,键的值不能重复,否则会引发该异常。这个异常通常是由于在使用集合类时,向一个已经存在的键插入了相同的键值对所导致的。具体来说,这个异常可能是由于使用了类似于HashMap或LinkedHashMap等可以存储键值对的集合类,并且向这个集合插入了重复的键值对。如果在代码出现了这个异常,可以通过检查代码逻辑,确保没有重复插入相同的键值对或者确保使用的集合类支持键的唯一性来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [java.lang.IllegalStateException: Duplicate key,异常](https://blog.csdn.net/weixin_40873693/article/details/124659750)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Stream ToMap(Collectors.toMap) 实践](https://blog.csdn.net/xiaolulululululu/article/details/86636203)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java异常之—-Caused by: java.lang.IllegalStateException: Method has too many Body parameters](https://download.csdn.net/download/weixin_38551143/14883721)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网全栈开发实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值