写点什么

不是吧,还有人不知道三目运算符的 BUG

作者:自然
  • 2022 年 9 月 14 日
    广东
  • 本文字数:1208 字

    阅读完需:约 4 分钟

前言

文本已收录至我的 GitHub 仓库,欢迎 Star:https://github.com/bin392328206/six-finger

种一棵树最好的时间是十年前,其次是现在

每篇一句

这世上每个人都背负着枷锁,有的人是别人给的,有的是自己给的。

絮叨

三目运算符一直是众多开发者信手拈来的一种写法,它简化了 if-else 的臃肿的写法,而是用一行代码替代,就感觉无形之中秀了一把。



殊不知,这么帅气的代码也暗藏着一个 BUG。

缘由

头天晚上发布了一个功能,本以为是波澜不惊的一个需求,结果第二天 kibana 打出了成吨的 NPE 日志。这些 NPE 日志大多都不约而同都指向了我写的一行代码,我立马推了下我的眼镜,开始排查起来了。



问题代码



Kibana 的堆栈日志定位在第 899 行。


resultMap.put("unAuditPurchaseOrder", switchConf == null ? 0 : switchConf.getUnAuditPurchaseOrder());


1.检查了 resultMap,它在上面有实例化,不可能为空。2.检查 switchConf,但是在这里有判空,也不会报错。 那是怎么回事????


继续排查

既然肉眼看不出,那么只能找一台测试机,用一下 Arthas 看一下具体的情况。(线上慎用,因为可能会造成卡顿)


trace com.raycloud.dmj.tj.services.customer.CustomerButtonService getPurchaseConfig -n 5 '1==1' --skipJDKMethod false
复制代码



果然,这里就发现了端倪。 这里竟然执行了 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
复制代码



然后我又改了一下程序


public class Test {
public static void main(String[] args) {
Integer i = null; System.out.println(1 == 1 ? 0 : i);
}}
复制代码


这次运行并不会报错,看一下它的 JVM 指令:



因为三目运算符的结果是前者的逻辑,即返回一个常量 0。

解释

由上面的实验可以发现,JVM 在解释三目运算符的时候,会对两个逻辑语句进行数据类型校验,按照前者的数据类型为准。实验中,数据类型是基本数据类型,所以,如果逻辑走到了后者,那么就会进行自动的拆箱。这个隐式的操作就是造成这个 BUG 的原因。


解决

既然知道原因了,那么只要统一数据类型就行:


public class Test {
public static void main(String[] args) {
Integer i = null; System.out.println(1 != 1 ? new Integer(0) : i);
}}
复制代码


然后按照惯例,我们还是看一下他的 JVM 指令:


拾遗

后来在无意之中发现,原来这个例子在《阿里巴巴开发手册》当中也有被记录



其实说的也是一回事情!


日常求赞

好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是真粉


创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见


六脉神剑 | 文 【原创】如果本篇博客有任何错误,请批评指教,不胜感激 !

发布于: 刚刚阅读数: 4
用户头像

自然

关注

还未添加个人签名 2020.03.01 加入

小六六,目前负责营收超百亿的支付中台

评论

发布
暂无评论
不是吧,还有人不知道三目运算符的BUG_Java core_自然_InfoQ写作社区