1. 自动拆箱出现 null
包装器类型自动拆箱为基础类型时极容易出现NPE。如下图示例,方法void initTask(int taskId),调用时taskId如果为 null
,则会出现NPE。正确做法是 可能为 null
的属性,一律声明为包装器,此外从外部获取的变量一定要检查 null
,进行防御式编程。
public void initTask(int taskId){
}
@Test
public void test(){
Integer taskId = extractFromRequest();
initTask(taskId);
}
2. 遍历集合 出现 null
集合List支持 foreach 遍历,但是如果List变量为null,则一定会发生空指针异常 NPE。如下代码所示,当ids为空时,会发生NPE。
正确做法,在遍历List之前,一定要进行空值检查。
List<Integer> ids = extractFromRequest();
for(Integer id: ids){
}
3. 集合数组中出现 null
此外集合 List 中对象可能为空,在遍历集合时,要检查集合中的对象是否为 Null,否则可能发生 NPE。
List<Integer> ids = extractFromRequest();
for(Integer id: ids){
System.out.println(id.toString());
}
4. Optional.of() 出现 null
Optional 是 Java 8 提供的一个工具类,它可以以更加优雅的方式来处理空值。在使用 Optional 类的时候,有两种初始化方式,分别是 Optional.of(object)
和 Optional.ofNullable(object)
。需要注意的是,在使用 Optional.of(object)
的时候,如果 object 为 null,就会发生空指针异常NPE。
正确做法:使用 Optional.ofNullable();
Optional.of(object);
5. Stream和 Lamada中出现 null
若在lambda表达式中出现了Null,就可能会发生空指针异常 NPE。具体示例如下图所示,当使用Stream.map方式进行映射时,可能会导致返回值为Null。
正确做法:filter(Objects::nonNull)
过滤为 Null 对象
List<Long> userIds = Lists.newArrayList(1L, 2L, 3L);
List<String> orderIds = userIds.stream()
.map((userId) -> {
OrderService.UserOrder order = getUserOrderFromDb(userId);
return order;
}).map(OrderService.UserOrder::getOrderId)
.collect(Collectors.toList());
6. json 解析出现 null
使用 fastjson 可能遇到解析的对象为 null 的情况。很多业务系统使用 json 存储扩展字段,一般情况下mysql 字段默认值为””或 null,这种情况使用 FastJson 解析时,就会解析出 null对象,不判空就会出现空指针异常。
如下代码所示,当传入的json 字符串为空值””时,解析出的 json 对象为 Null。
UserOrder his = JSON.parseObject("{}", UserOrder.class);
Map<String, String> jsonMap = JSONObject.parseObject(ext_json,
new TypeReference<HashMap<String,String>>(){});
7. 打印日志使用 + 号出现 null
日志打印时,很多人习惯使用 + 加号拼接日志,这种情况可能导致 空指针异常。
正确做法:使用{}占位符方式,打印变量。 日志框架会进行判空,当变量出现 Null 时,不会出现空指针。
很多人在 review 代码时,不重视日志代码,容易忽略日志代码中的问题。曾经有个同事搞出的线上问题就是因为日志打印出现了 NPE。
一定要敬畏每一行代码,包括日志代码。
8. 返回值异常处理
如下所示,业务系统在调用 Rpc 后,会对结果判空和检查异常码。如果调用失败,则会上报异常码。然而这两者不能完全放在一起,因为当 result 为 null 时,上报异常码会导致空指针异常的发生。
RpcResult result = invokeRpcMethod();
if(result==null || result.getCode!=SUCCESS){
log.error("调用失败 result:{}", result);
reportCode(result.getCode());
}
没有回复内容