总结Java 空指针异常隐藏最深的8 个场景

Java

1. 自动拆箱出现 null

包装器类型自动拆箱为基础类型时极容易出现NPE。如下图示例,方法void initTask(int taskId),调用时taskId如果为 null,则会出现NPE。正确做法是 可能为 null 的属性,一律声明为包装器,此外从外部获取的变量一定要检查 null,进行防御式编程。

public void initTask(int taskId){
    // do something
}

@Test
public void test(){
  Integer taskId = extractFromRequest();
  // 若taskId为Null,则一定发生NPE
  initTask(taskId);
}

2. 遍历集合 出现 null

集合List支持 foreach 遍历,但是如果List变量为null,则一定会发生空指针异常 NPE。如下代码所示,当ids为空时,会发生NPE。

正确做法,在遍历List之前,一定要进行空值检查。


List<Integer> ids = extractFromRequest();
//如果ids为 null,则发生 NPE
for(Integer id: ids){
   //do something
}

新人跳板机会>>>技术大厂,前端-后端-测试,待遇还可以,有需要试试。

3. 集合数组中出现 null

此外集合 List 中对象可能为空,在遍历集合时,要检查集合中的对象是否为 Null,否则可能发生 NPE。

List<Integer> ids = extractFromRequest();
//如果ids为 null,则发生 NPE
for(Integer id: ids){
   // id可能为 null,则会发生 NPE
   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); //若 object 为 null,则会发生 NPE。

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);
                       //若order 为空,则下方出现 NPE。
                       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);

//从数据库中获取ext_json。当为 null或""时,会出现 null
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);
     //当 result 为空时,则一定发生空指针。
     reportCode(result.getCode());
}

——转载自:五阳

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动云原生降本增效实践
本次分享主要介绍字节跳动如何利用云原生技术不断提升资源利用效率,降低基础设施成本;并重点分享字节跳动云原生团队在构建超大规模云原生系统过程中遇到的问题和相关解决方案,以及过程中回馈社区和客户的一系列开源项目和产品。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论