第一种情况:
手册原话是:
在使用 java.util.stream.Collectors 类的 toMap()方法转为 Map 集合时,一定要使用含有参数类型为 BinaryOperator,参数名为 mergeFunction 的方法,否则当出现相同 key 值时会抛出 IllegalStateException 异常。
其中mergeFunction函数就是用于处理key冲突的情况,BinaryOperator<T>接口用于执行lambda表达式并返回一个T类型的返回值。
这句话的通俗解释就是,当存在相同的key时执行toMap方法会报错。可以看下面的实际运行情况:
public class StreamTest {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person(1011,"A"));
personList.add(new Person(1012,"B"));
personList.add(new Person(1013,"C"));
Map<Integer,String> personMap= personList.stream().collect(Collectors.toMap(Person::getId,Person::getName));
System.out.println(personMap);
}
}
如果存在重复的key的运行结果(将"C"的key改为1012):
果不其然报错了,而且错误提醒十分明白。那怎么解决呢?
这个得根据不同业务场景采用不同的办法,今天列举两个比较常见的:
1. 对于重复的key,只记录其中一个,可以用后面的value替换前面的value,当然也可以用前面的value替换后面的value。
Map<Integer,String> personMap= personList.stream()
.collect(Collectors.toMap(Person::getId,Person::getName,(key1,key2) -> key2));
2.对于重复的key,将重复key的数据组成集合
Map<Integer,List<String>> personMap= personList.stream().collect(Collectors.toMap(Person::getId,
// 将value转为集合,方便重复时操作
p -> {
List<String> personNameList = new ArrayList<>();
personNameList.add(p.getName());
return personNameList;
},
// 重复时将后面的值添加到之前的值内
(List<String> value1, List<String> value2) -> {
value1.addAll(value2);
return value1;
}
));
用了两个lambda表达式,但是原则不变,第二个参数是value,第三个参数就是用来处理重复key的。
这里需要注意返回的map中的value要改为list参数。
第二种情况:
手册原话是:
在使用 java.util.stream.Collectors 类的 toMap()方法转为 Map 集合时,一定要注意当 value 为 null 时会抛 NPE 异常。
这个问题很好理解,那需要解决的就是避免抛出异常。问题复现很简单,这里直接说结果:
1. 设置时加判断如果是null,则设置成一个特定值。
Map<Integer,String> personMap= personList.stream()
.collect(Collectors.toMap(Person::getId,
person -> person.getName() == null ? "null" : person.getName()));
2. 利用Optional<T>对值进行包装
Map<Integer,String> personMap= personList.stream().collect(Collectors.toMap(Person::getId,
person -> Optional.ofNullable(person.getName()).orElse("null"),(key1, key2) -> key2));
建议采用第2个方法,可以同时避免key重复和value为null的情况。