记录一下 Java8 Stream 流操作中 Collectors.toMap() 操作当 value 为 null 时报空指针的问题以及解决方案。
问题代码:
@Override
public Map<Long, String> getEmployeeIdCompanyLicenseNoMap(Collection<Long> employeeIds) {
if (CollectionUtils.isEmpty(employeeIds)) {
return Collections.emptyMap();
}
List<EmployeeCompanyLicenseNoDTO> relationList = baseMapper.getEmployeeCompanyLicenseNoList(employeeIds);
if (CollectionUtils.isEmpty(relationList)) {
return Collections.emptyMap();
}
return relationList
.stream()
.collect(Collectors.toMap(
EmployeeCompanyLicenseNoDTO::getEmployeeId,
EmployeeCompanyLicenseNoDTO::getCompanyLicenseNo);
}
上面这段代码目的是查询员工 id 与其所属公司的营业执照编号的对应关系。其中有些员工是没有公司的,查询出来的营业执照编号将是 null。
运行这段代码后收到一个空指针异常,断点查看 relationList 的数据,其中有部分数据的 companyLicenseNo 字段值为 null
。很是疑惑,之前用了那么久的 toMap 方法都没有问题呀?而且 Map 的 value 是允许有多个 null 值的呀?为什么这里就不行了。光是想肯定没有用,带着这些疑问点开源码,看看最终是哪一步调用导致的空指针异常。
从图中可以看出来,最终实际上是调用的图片右侧的 toMap 方法,可以看到右侧绿色框的代码,有一句 (map, element) -> map.merge(keyMapper.apply(element),
,而 map
根据函数签名上的泛型定义 public static <T, K, U, M extends Map<K, U>>
可以知道,map
变量表示的是 Map
接口,并且调用了 Map 接口的 merge
方法。跟着点开对应源码:
可以看到,Map 接口中 merge 方法有个默认实现,其中对 value 进行了判空的操作,但是我们可以这里调用 toMap 操作的时候默认 new 的是 HashMap 的实例。而 HashMap 是 Map 的实现类之一,因此我们点开 HashMap 的 merge 方法。
可以看到 HashMap
的 merge
方法也是对 value 进行了判空操作的,因此问题的原因也就找到了。
在网上找了一圈,最终采用的解决方案就是放入 value 的时候判断一下,如果是 null 则放入一个空字符串或者是其他不具有业务含义的值来代替。
以下是其中一种写法:
@Override
public Map<Long, String> getEmployeeIdCompanyLicenseNoMap(Collection<Long> employeeIds) {
if (CollectionUtils.isEmpty(employeeIds)) {
return Collections.emptyMap();
}
List<EmployeeCompanyLicenseNoDTO> list = baseMapper.getEmployeeCompanyLicenseNoList(employeeIds);
if (CollectionUtils.isEmpty(list)) {
return Collections.emptyMap();
}
return list
.stream()
.collect(Collectors.toMap(
EmployeeCompanyLicenseNoDTO::getEmployeeId,
it -> Optional.ofNullable(it.getCompanyLicenseNo()).orElse(CommonConstant.EMPTY_STR)));
}
0 条评论