stream流Collectors.toMap(),key值重复问题

一、问题

发现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;
}

输出结果:

{
    
    张三=}

可以看到最后的效果是使用新的值替换旧的值。所以输出的是