java8 Stream API中Collectors中toMap方法的问题以及解决

解决异常:java.lang.IllegalStateException: Duplicate key **

最近在项目中使用java8的list 转 map的时候遇到了重复值的异常:

Exception in thread "main" java.lang.IllegalStateException: Duplicate key Person@568db2f2  
    at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)  
    at java.util.HashMap.merge(HashMap.java:1245)  
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)  
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) 

1、写了测试类重现异常:

在业务场景中出现重复值的时候我们希望使用新的值替换之前的值:

public static void main(String[] args) {  
        Person a1= new Person("p","p1");  
        Person a2= new Person("p","p2");  
        Person a3= new Person("p1","p3");  
  
        List<Person> list = new ArrayList<Person>();  
        list.add(a1);  
        list.add(a2);  
        list.add(a3);  
        //下面这句会出异常java.lang.IllegalStateException: Duplicate key  
        Map<String, Person> map1 = list.stream().collect(Collectors.toMap(Person::getName , (p) -> p));          
          
    }  
  
class Person {  
    private String name;  
    private String sex;  
  
    public Person(String name, String sex) {  
        super();  
        this.name = name;  
        this.sex = sex;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public String getSex() {  
        return sex;  
    }  
    public void setSex(String sex) {  
        this.sex = sex;  
    }     
} 

这段代码会抛出开头贴出来的异常:java.lang.IllegalStateException: Duplicate key **

总结一下:

使用Collectors.toMap方法时的两个问题:
1、当key重复时,会抛出异常:java.lang.IllegalStateException: Duplicate key **
2、当value为null时,会抛出异常:java.lang.NullPointerException

大家通常希望这个方法是可以容错的,遇到重复的key就使用后者替换,而且HashMap的value可以是null。

将之前出错的代码调整如下:

//下面这句会出异常java.lang.IllegalStateException: Duplicate key  
Map<String, Person> map1 = list.stream().collect(Collectors.toMap(Person::getName , (p) -> p));  
//修改为下面这句  
Map<String, Person> map2 = list.stream().collect(Collectors.toMap(Person::getName , (p) -> p,(k,v)->v));  

记录一下:

//1.针对重复key的  覆盖之前的value  
list.stream().collect(Collectors.toMap(Person::getName, Person::getSex,(k,v)->v));  
  
//2.value为空,直接存放  不调用map.merge。同样适用于1(key重复的情况)  
list.stream().collect(Collector.of(HashMap::new, (m,per)->m.put(per.getName(),per.getSex()), (k,v)->v, Characteristics.IDENTITY_FINISH));  
  
//其中lambda表达式: (k,v)->v   不会被调用,但是又不能为空  
原文链接:,转发请注明来源!

发表评论

要发表评论,您必须先登录