一、问题
发现Collectors.toMap的一个坑,若key值重复的时候会抛异常。如: IllegalStateException: Duplicate key 男
二、问题示例
报错示例如下:
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.*;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args){
List<User> list = new ArrayList<>();
User u1 = new User("张三","男");
User u2 = new User("张三","女");
list.add(u1);
list.add(u2);
//key:姓名 value:性别
Map<String,String> userMap = list.stream().collect(Collectors.toMap(User::getName, User::getSex));
System.out.println(userMap);
}
}
@Data
@AllArgsConstructor
class User{
//姓名
private String name;
//性别
private String sex;
}
报错信息:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 男
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 com.springboot.store.Test.main(Test.java:17)
三、原因
根据上面报错信息找到报错代码,
java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
四、解决方法
4.1、方案一
为了解决key值重复情况,你可以通过提供一个合并函数来解决键冲突的问题。下面是一个示例,展示了如何使用 toMap 的四参数版本来避免抛出异常,并选择保留最后一个值:
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.*;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args){
List<User> list = new ArrayList<>();
User u1 = new User("张三","男");
User u2 = new User("张三","女");
list.add(u1);
list.add(u2);
//key:姓名 value:性别
Map<String,String> userMap = list.stream().collect(Collectors.toMap(User::getName, User::getSex,(oldValue,newValue)->newValue));
System.out.println(userMap);
}
}
@Data
@AllArgsConstructor
class User{
//姓名
private String name;
//性别
private String sex;
}
输出结果:
{
张三=女}
可以看到最后的效果是使用新的值替换旧的值。所以输出的是女