Collectors.toMap在在处理null值时,会出现NullPointerException
示例
DishCategoryAllPO d1 = new DishCategoryAllPO();
d1.setDishId(11111);
d1.setPrimaryLabel("11111");
DishCategoryAllPO d2 = new DishCategoryAllPO();
d2.setDishId(11111);
DishCategoryAllPO d3 = new DishCategoryAllPO();
d3.setDishId(22222);
DishCategoryAllPO d4 = new DishCategoryAllPO();
d4.setDishId(22222);
d4.setPrimaryLabel("22222");
DishCategoryAllPO d5 = new DishCategoryAllPO();
d5.setDishId(33333);
List<DishCategoryAllPO> list = Arrays.asList(d1, d2, d3, d4, d5);
Map<Integer, String> map = list.stream().collect(Collectors.toMap(DishCategoryAllPO::getDishId, DishCategoryAllPO::getPrimaryLabel,
(existing, replacement) -> existing));
map.forEach((k,v) -> System.out.println(k+" "+v));
在这个例子中,d2和d5对象的primaryLabel属性没有被设置,即它们为null。当尝试将这些null值插入到Map中时,就会抛出NullPointerException。
原因
当尝试将null值插入到Map中时抛出NullPointerException的原因涉及到Jav 8 Collectors.toMap()方法的内部实现。具体来说:
- Collectors.toMap()内部使用HashMap来存储结果。
- 在Java 8中,HashMap的merge()方法被用来处理键值对的插入和合并。
- merge()方法在处理值为null的情况时有一个特殊的逻辑:如果新值为null,它会尝试删除已存在的键值对。
- 然而,在Collectors.toMap()的实现中,merge()方法被调用时假设了值永远不会为null。
- 当遇到null值时,merge()方法会尝试对null执行操作,从而导致NullPointerException。
⠀
经验教训
-
这个问题在Java 9中得到了修复,通过改变Collectors.toMap()的实现来正确处理null值。但在Java 8中,这个问题仍然存在。
-
Map<Integer, String> map = list.stream() .collect(Collectors.toMap(DishCategoryAllPO::getDishId, dish -> dish.getPrimaryLabel() != null ? dish.getPrimaryLabel() : "默认值", // 提供默认值 (existing, replacement) -> existing));
-
Map<Integer, String> map = list.stream() .filter(dish -> dish.getPrimaryLabel() != null) // 过滤掉primaryLabel为null的元素 .collect(Collectors.toMap(DishCategoryAllPO::getDishId, DishCategoryAllPO::getPrimaryLabel, (existing, replacement) -> existing));