Java中的条件运算符(又称三目运算符,形如 b ? x : y),相信很多人都不陌生。其只需一条语句即可完成 if else 代码块的功能,故日常开发中也是高频操作,但是稍有不慎、姿势不对,就会掉入自动拆箱的陷阱中发生NPE(Null Pointer Exception)
复现异常
我们先来做一个简单的测试,下述测试代码quickTest1() 预期结果应该是输出 “b : null”
1 | public static void quickTest1() { |
执行结果,却恰恰出乎意料,发生了NPE
分析异常
使用javap工具对上述测试用例生成的class字节码文件进行反编译
从上图可以看出,a变量进行的自动拆箱操作,而由于其值为null,故调用 a.intValue() 出现了NPE,所以实际最终执行的代码如下所示:
1 | Integer b = Integer.valueOf( true ? a.intValue() : 12 ); |
解决方案
自动装箱、拆箱是在JDK1.5后引入的新功能,在平时开发过程中,可以大大方便我们,但是其也有可能会成为Bug之源。在Java的条件运算符( b ? x : y)中,当x和y的类型不一致时,即发生自动拆箱,将x,y全部转换成基本类型。上述例子中,x表达式为变量a——Integer类型,而y表达式为12——int基本类型。类型不一致,所以即对变量a进行自动拆箱
对于如何避免发生NPE,这里给出两种解决方案:
- 不使用条件运算符,改用传统的if-else语句块
- 保证x、y表达式类型一致,避免发生自动拆箱
我们根据第二种方案,重新改写我们之前的测试代码,这里我们通过显式转换将x、y表达式均统一为Integer
1 | public static void quickTest2() { |
反编译该方法的class字节码文件,可以看到没有发生自动拆箱操作
其方法执行结果,符合我们的预期且未发生NPE