一、背景
在我们的日常工作中,我们会经常遇到空指针问题,理论上来说只是一个判段空指针的小问题,但是因为这行代码的报错,程序中断了后面的执行,可能导致整体业务逻辑受影响。那在工作中我们应该如何避免,或者说降低空指针的发生。下面讲一下我的个人感悟
二、如何避免或者减少空指针问题的发生
(1)使用对象时养成不信任意识
一定要记住无论用什么方法避免空指针,最好的手段永远是不信任意识,只有不信任意识养成了,我们在写代码的时候在用一个对象的时候,自然而然就会想到这个对象是否会为空,只有这层意识养成了,你才能避免绝大多数空指针场景
在这里将我们一般常用的对象总结一下
- 自己手动new出来的对象
- 从数据库查询数据转换出来的查询对象(一般是一个集合)
- 框架(一般大家都是用Spring全家桶)帮我们创建的对象
- 通过调用外部接口返回的数据形成的数据对象
- .........
在我们使用对象的时候都要有不信任的意识,他是否为空对象,对象里面的对象是否为空对象。这样才能大概率避免空指针场景
(2)使用JDK1.8特性 Optional工具封装方法
Optional有两个用法
- 封装方法返回值
我们来看这样一段方法
假设会员积分超过1000,则返回一台电脑,然后用电脑玩
/**
* @author chen
* @description 如果会员积分大于1000则奖励一台电脑
* @param memberPointsNumber 会员积分
* @date: 2024/8/6 11:06
* @return bio.Computer
*/
public Computer getComputer(int memberPointsNumber){
if(memberPointsNumber < 1000){
return null;
}
return new Computer();
}
假设我们使用的时候是这样,直接调用,则就可能会出现空指针的现象,所以这个非常取决于调用者的意识,调用者意识好,会进行空指针判断,则可以避免
Computer computer = testDemo.getComputer(800);
//拿到这个对象直接判空则会引发空指针
computer.doPlayGame();
Exception in thread "main" java.lang.NullPointerException
at CopyArrayListDemo.main(CopyArrayListDemo.java:21)
我们可以使用Optional进行改进一下
/**
* @author chen
* @description 如果会员积分大于1000则奖励一台电脑
* @param memberPointsNumber 会员积分
* @date: 2024/8/6 11:06
* @return bio.Computer
*/
public Optional<Computer> getComputer(int memberPointsNumber){
if(memberPointsNumber < 1000){
return Optional.empty();
}
return Optional.of(new Computer());
}
如果调用者不进行空判断,则IDEA会自己进行深颜色告警
所以我们正确的写法是,利用Optional的特性对使用对象进行检查,借助Optional特性让调用方强制检查,从而减少空指针的发生
Optional<Computer> computerOptional = testDemo.getComputer(800);
//使用Optional的特性进行判空
if(!computerOptional.isPresent()) {
return;
}
Computer computer = computerOptional.get();
computer.doPlayGame();
- 嵌套对象获取
在没使用Optional时,我们获取嵌套对象如果需要判空则需要这样做
举一个获取Computer类的USB类的版本号为例,需要获取对象判断空指针,如果对象嵌套层级深要判断多次空指针
Computer computer = computerOptional.get();
//获取USB对象
USB usb = computer.getUsb();
Integer version = 1;
if(Objects.nonNull(usb)){
version = usb.getVersion();
}
System.out.println("USB 版本号是 : " + version);
我们也可以使用Optional来这样写,代码更加简洁,以及工具会帮我们进行空指针判断
Computer computer = computerOptional.get();
//使用Optional来进行获取版本号,简化代码的同时以及能做到空指针判断
Integer version = Optional.of(computer).map(Computer::getUsb).map(USB::getVersion).orElse(1);
System.out.println("USB 版本号是 : " + version);
(3)使用Hutool转换类进行转换
在我们的工作中,数据转换是我们常常会遇见的,例如String转Integer,Integer转Double等等,Hutool工具包里面帮我们提供了工具类转换,即使转换失败也不会报错,可以大大提高代码的健壮性,举String转Integer为例
我们一般这样写,代码存在风险,Integer.parseInt方法不会判空,如果字符串不是数字也会报错
String a = "123";
//Integer.parseInt方法不会判空,如果字符串不是数字也会报错
Integer result = Integer.parseInt(a);
假设我们使用hutool工具包提供的类,代码很稳定,即使变量a是非数字也不会报错,转换的api也很丰富,也支持转换失败返回默认值,具体可以去hutool工具官网上了解
类型转换工具类-Convert | Hutool
String a = "123";
Integer result = Convert.toInt(a);
(4)代码扫描工具
代码扫描工具很多公司都是自己搭建的,这个不详细说了,比较火的有FindBugs、PMD、SonarQube、Fortify、WebInspect,对于一些常规的空指针错误是能够帮你扫描出来的,也算是减少或者避免空指针问题的工具
三、总结
任何工具都是辅助,就像我之前说的,只有不信任意识才是最终的道路,可以结合工具,然后逐步养成不信任意识,在写代码的道路上越来越严谨,出问题的概率当然就越来越小。祝愿大家写的代码越来越越稳如泰山。