解決使用stream將list轉(zhuǎn)map時(shí),key重復(fù)導(dǎo)致報(bào)錯(cuò)的問(wèn)題
要將List對(duì)象集合轉(zhuǎn)為map集合,可以通過(guò)stream流的形式快速實(shí)現(xiàn)轉(zhuǎn)換:
//三個(gè)Users對(duì)象組成一個(gè)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轉(zhuǎn)map Map<String, Users> usersMap = list.stream() .collect(Collectors.toMap(Users::getUserName, user -> user)); System.out.println(usersMap.get("11"));
但是上述代碼運(yùn)行后報(bào)了異常:
意思為map中出現(xiàn)了重復(fù)的key,也就是說(shuō)通過(guò)上述方法轉(zhuǎn)map時(shí),出現(xiàn)重復(fù)key并不會(huì)出現(xiàn)覆蓋的情況,而是再次在map中添加一個(gè)重復(fù)的key,導(dǎo)致報(bào)錯(cuò)。
所以通過(guò)stream實(shí)現(xiàn)list轉(zhuǎn)map時(shí),要實(shí)現(xiàn)重復(fù)的key會(huì)被覆蓋,可以使用Function.identity()方法:
//三個(gè)Users對(duì)象組成一個(gè)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轉(zhuǎn)map,這里是出現(xiàn)重復(fù)key時(shí),覆蓋前一個(gè) Map<String, Users> usersMap = list.stream() .collect(Collectors.toMap(Users::getUserName, Function.identity(), (user1, user2) -> user2)); System.out.println(usersMap.get("11")); //輸出結(jié)果: edu.nf.ch08.entity.Users@41aaedaa
JDK 8 Stream List轉(zhuǎn)換為Map的duplicate Key異常
Stream List to Map
Stream提供了List轉(zhuǎn)換為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); }
其在轉(zhuǎn)換過(guò)程中,會(huì)拋出異常:
@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
如何解決
增加重復(fù)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
總結(jié)
在Collectors.toMap()轉(zhuǎn)換過(guò)程中,需要注意一下duplicate key的處理邏輯,需要增加mergeFunction()處理方法。以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家
- 詳解Java8新特性Stream之list轉(zhuǎn)map及問(wèn)題解決
- Java8 實(shí)現(xiàn)stream將對(duì)象集合list中抽取屬性集合轉(zhuǎn)化為map或list
- JDK8通過(guò)Stream 對(duì)List,Map操作和互轉(zhuǎn)的實(shí)現(xiàn)
- java8 Stream list to Map key 重復(fù) value合并到Collectio的操作
- Java8 中使用Stream 讓List 轉(zhuǎn) Map使用問(wèn)題小結(jié)
- 關(guān)于List、Map、Stream初始化方式
- Java中List使用stream流轉(zhuǎn)成map的幾種方式詳解
相關(guān)文章
Spring動(dòng)態(tài)配置計(jì)時(shí)器觸發(fā)時(shí)間的實(shí)例代碼
這篇文章主要介紹了Spring動(dòng)態(tài)配置計(jì)時(shí)器觸發(fā)時(shí)間的實(shí)例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06MP(MyBatis-Plus)實(shí)現(xiàn)樂(lè)觀鎖更新功能的示例代碼
這篇文章主要介紹了MP(MyBatis-Plus)實(shí)現(xiàn)樂(lè)觀鎖更新功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Java核心編程之文件隨機(jī)讀寫(xiě)類(lèi)RandomAccessFile詳解
這篇文章主要為大家詳細(xì)介紹了Java核心編程之文件隨機(jī)讀寫(xiě)類(lèi)RandomAccessFile,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08淺談web服務(wù)器項(xiàng)目中靜態(tài)請(qǐng)求和動(dòng)態(tài)請(qǐng)求處理
這篇文章主要介紹了淺談web服務(wù)器項(xiàng)目中靜態(tài)請(qǐng)求和動(dòng)態(tài)請(qǐng)求處理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07使用java的HttpClient實(shí)現(xiàn)多線程并發(fā)
這篇文章主要介紹了使用java的HttpClient實(shí)現(xiàn)多線程并發(fā)的相關(guān)資料,需要的朋友可以參考下2016-09-09SpringBoot使用Jwt處理跨域認(rèn)證問(wèn)題的教程詳解
這篇文章主要介紹了SpringBoot使用Jwt處理跨域認(rèn)證問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06