解决使用stream将list转map时,key重复导致报错的问题

 更新时间:2021年06月10日 11:03:03   作者:张财华  
这篇文章主要介绍了解决使用stream将list转map时,key重复导致报错的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

要将List对象集合转为map集合,可以通过stream流的形式快速实现转换:

//三个Users对象组成一个List集合
List<Users> list = new ArrayList<>();
list.add(Users.builder().userName("11").userId(1).build());
list.add(Users.builder().userName("11").userId(2).build());
list.add(Users.builder().userName("33").userId(3).build());
//将list转map
Map<String, Users> usersMap = list.stream()
    .collect(Collectors.toMap(Users::getUserName, user -> user));
System.out.println(usersMap.get("11"));

但是上述代码运行后报了异常:

意思为map中出现了重复的key,也就是说通过上述方法转map时,出现重复key并不会出现覆盖的情况,而是再次在map中添加一个重复的key,导致报错。

所以通过stream实现list转map时,要实现重复的key会被覆盖,可以使用Function.identity()方法:

//三个Users对象组成一个List集合
List<Users> list = new ArrayList<>();
list.add(Users.builder().userName("11").userId(1).build());
list.add(Users.builder().userName("11").userId(2).build());
list.add(Users.builder().userName("33").userId(3).build());
//将list转map,这里是出现重复key时,覆盖前一个
Map<String, Users> usersMap = list.stream()
    .collect(Collectors.toMap(Users::getUserName, Function.identity(), (user1, user2) -> user2));
System.out.println(usersMap.get("11"));
//输出结果:
edu.nf.ch08.entity.Users@41aaedaa

JDK 8 Stream List转换为Map的duplicate Key异常

Stream List to Map

Stream提供了List转换为Map提供了非常易用的方法:

Collectors.java:

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);
    }

其在转换过程中,会抛出异常:

 @Test(expected = IllegalStateException.class)
    public void testStreamMap_duplicateKey() {
        Employee employee = Employee.builder().id(1).age(20).firstName("zhang").build();
        Employee employee1 = Employee.builder().id(2).age(21).firstName("Li").build();
        Employee employee2 = Employee.builder().id(3).age(22).firstName("Li").build();
        Employee employee3 = Employee.builder().id(4).age(23).firstName("Chen").build();
        List<Employee> employees = Lists.newArrayList();
        employees.add(employee);
        employees.add(employee1);
        employees.add(employee2);
        employees.add(employee3);
        Map<String, Integer> dataMap = employees.stream().collect(Collectors.toMap(e -> e.getFirstName(), e -> e.getAge()));
        //Duplicate Key
        Map<Integer, Employee> employeeMap = employees.stream().collect(Collectors.toMap(e->e.getAge(), e->e));
    }

抛出异常信息:

java.lang.IllegalStateException: Duplicate key 21
 at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
 at java.util.HashMap.merge(HashMap.java:1254)
 at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
 at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
 at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
 at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
 at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
 at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
 at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
 at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
 at org.cjf.java.learn.jdk8.StreamTest.testStreamMap_duplicateKey(StreamTest.java:90)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
 at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
 at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
 at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
 at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
 at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
 at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
 at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
 at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
 at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
 at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
 at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
 at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
 at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
 at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
 at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
 at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Process finished with exit code 255

如何解决

增加重复key情况下的冲突处理策略:

 Map<String, Integer> dataMap = employees.stream().collect(Collectors.toMap(e -> e.getFirstName(), e -> e.getAge(), (k1, k2)-> k1));
        Assert.assertThat(dataMap, hasKey("zhang"));
        Assert.assertThat(dataMap, hasKey("Li"));
        Assert.assertThat(dataMap, hasKey("Chen"));
        Assert.assertThat(dataMap.keySet(), hasSize(3));
        Map<Integer, Employee> employeeMap = employees.stream().collect(Collectors.toMap(e->e.getAge(), e->e, (k1, k2) -> k1));
        Assert.assertThat(dataMap.keySet(), hasSize(3));

这里的处理策略是:

(k1, k2) -> k1

总结

在Collectors.toMap()转换过程中,需要注意一下duplicate key的处理逻辑,需要增加mergeFunction()处理方法。以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家

相关文章

  • 实战讲解Maven安装及基本使用详解

    实战讲解Maven安装及基本使用详解

    这篇文章主要介绍了实战讲解Maven安装及基本使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • JavaEE的进程,线程和创建线程的5种方式详解

    JavaEE的进程,线程和创建线程的5种方式详解

    这篇文章主要为大家详细介绍了JavaEE的进程,线程和创建线程的5种方式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • Netty分布式抽象编码器MessageToByteEncoder逻辑分析

    Netty分布式抽象编码器MessageToByteEncoder逻辑分析

    这篇文章主要介绍了Netty分布式抽象编码器MessageToByteEncoder的抽象逻辑分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • SpringBoot和Vue实现动态二维码的示例代码

    SpringBoot和Vue实现动态二维码的示例代码

    二维码在现代社交和营销活动中被广泛使用,本文主要介绍了SpringBoot和Vue实现动态二维码的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-02-02
  • 关于java 图形验证码的解决方法

    关于java 图形验证码的解决方法

    本篇文章小编为大家介绍,在java中,使用图形验证码的解决方法。需要的朋友参考下
    2013-04-04
  • Springboot+Shiro记录用户登录信息并获取当前登录用户信息的实现代码

    Springboot+Shiro记录用户登录信息并获取当前登录用户信息的实现代码

    这篇文章主要介绍了Springboot+Shiro记录用户登录信息,并获取当前登录用户信息,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-05-05
  • SpringBoot实现JWT token自动续期的示例代码

    SpringBoot实现JWT token自动续期的示例代码

    本文主要介绍了SpringBoot实现JWT token自动续期的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Java调用腾讯云短信API接口的实现

    Java调用腾讯云短信API接口的实现

    这篇文章主要介绍了Java调用腾讯云短信API接口的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Intellj Idea中的maven工程Java文件颜色不对,未被识别的解决

    Intellj Idea中的maven工程Java文件颜色不对,未被识别的解决

    这篇文章主要介绍了Intellj Idea中的maven工程Java文件颜色不对,未被识别的解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Java创建线程的五种写法总结

    Java创建线程的五种写法总结

    本文主要为大家详细介绍一下Java实现线程创建的五种写法,文中的示例代码讲解详细,对我们学习有一定的帮助,感兴趣的可以跟随小编学习一下
    2022-08-08

最新评论