三目运算符一直是众多开发者信手拈来的一种写法,它简化了if-else的臃肿的写法,而是用一行代码替代,就感觉无形之中秀了一把。
![8520b5877f48f31d2802b6f051fcca75.png](https://i-blog.csdnimg.cn/blog_migrate/a31c76b4211d2440b95d2f8040f28ec6.jpeg)
殊不知,这么帅气的代码也暗藏着一个BUG。
缘由
头天晚上发布了一个功能,本以为是波澜不惊的一个需求,结果第二天kibana打出了成吨的NPE日志。这些NPE日志大多都不约而同都指向了我写的一行代码,我立马推了下我的眼镜,开始排查起来了。
![fc3ad9f9f07d3eb1d2e1fdadca0de4f2.png](https://i-blog.csdnimg.cn/blog_migrate/9a48af6e590d3a5291efb63bcab1571e.jpeg)
问题代码
![77d72f6308cd6806f18e10ff3c65b173.png](https://i-blog.csdnimg.cn/blog_migrate/a5e2283ec01745cbf809c141a0136779.png)
Kibana的堆栈日志定位在第899行。
resultMap.put("unAuditPurchaseOrder", switchConf == null ? 0 : switchConf.getUnAuditPurchaseOrder());
1.检查了resultMap,它在上面有实例化,不可能为空。
2.检查switchConf,但是在这里有判空,也不会报错。 那是怎么回事????
![d64a33c7180f40ad61a87b2c14c7a08e.png](https://i-blog.csdnimg.cn/blog_migrate/4a7040d6e98fa1fd30270b996249893a.png)
继续排查
既然肉眼看不出,那么只能找一台测试机,用一下Arthas看一下具体的情况。(线上慎用,因为可能会造成卡顿)
trace com.raycloud.dmj.tj.services.customer.CustomerButtonService getPurchaseConfig -n 5 '1==1' --skipJDKMethod false
![b65cab25cf329fc91a4f4bf031615eec.png](https://i-blog.csdnimg.cn/blog_migrate/8438db07f5f694e278c2c057ea059bdc.jpeg)
果然,这里就发现了端倪。 这里竟然执行了intValue()!也就是说如果switchConf.getUnAuditPurchaseOrder()
这个是null,那么就很明显发生了NPE。
看一下字节码
为了显现效果,我换一个简单的程序
public class Test {
public static void main(String[] args) {
Integer i = null;
System.out.println(1 != 1 ? 0 : i);
}
}
定位到class文件目录,执行
javap -c -l Test
![5440ddb1e74de0efb5dca6643e8f8a93.png](https://i-blog.csdnimg.cn/blog_migrate/fcad19ba1285926d6cbc0921135778d3.jpeg)
然后我又改了一下程序
public class Test {
public static void main(String[] args) {
Integer i = null;
System.out.println(1 == 1 ? 0 : i);
}
}
这次运行并不会报错,看一下它的JVM指令:
![f4adb5672d0f5d22810e203753b964a8.png](https://i-blog.csdnimg.cn/blog_migrate/4f9ce62e7435b9caffb076b2e59b7215.jpeg)
因为三目运算符的结果是前者的逻辑,即返回一个常量0。
解释
由上面的实验可以发现,JVM在解释三目运算符的时候,会对两个逻辑语句进行数据类型校验,按照前者的数据类型为准。实验中,数据类型是基本数据类型,所以,如果逻辑走到了后者,那么就会进行自动的拆箱。这个隐式的操作就是造成这个BUG的原因。
![9e7dbae5b4da473747cff21324af5a51.png](https://i-blog.csdnimg.cn/blog_migrate/e38dbd04428bf9484246a4adf7ad497b.jpeg)
解决
既然知道原因了,那么只要统一数据类型就行:
public class Test {
public static void main(String[] args) {
Integer i = null;
System.out.println(1 != 1 ? new Integer(0) : i);
}
}
然后按照惯例,我们还是看一下他的JVM指令:
![345edf017e34eb2cbffc783c742f078d.png](https://i-blog.csdnimg.cn/blog_migrate/3b222c54d5591c5b2259103b2db56519.jpeg)
拾遗
后来在无意之中发现,原来这个例子在《阿里巴巴开发手册》当中也有被记录
![349a7fb8195a963af77940b401cd16c2.png](https://i-blog.csdnimg.cn/blog_migrate/615e8e5d248de105a9038158dcad6cf4.jpeg)
其实说的也是一回事情!
后续
最后,虽然问题是解决了,但我还是被测试同学记录了一下黑名单,这锅得背~
原文:不是吧,还有人不知道三目运算符的BUG - 掘金
作者: 浮沉_fuchen