文章目录

  • 一、诡异的NPE
  • 二、原因:三目运算符表达式类型对齐拆箱导致NPE
  • 三、继续深究
  • 四、总结

情况这段代码:

一、诡异的NPE

报错信息如下:

2020-06-03 13:02:22.193 [] [DubboServerHandler-120889-thread-8] ERROR com.alibaba.dubbo.rpc.filter.ExceptionFilter 90 -
[DUBBO] Got unchecked and undeclared exception which called by .
service: com.jzd.health.archive.api.si.DiseaseHistoryServiceInterface, method: getRemovedDuplicateFamilyDiseaseNames, exception: java.lang.NullPointerException: null, dubbo version: 2.8.4.1, current host:
java.lang.NullPointerException: nullat com.jzd.health.archive.biz.service.transform.DiseaseHistoryTransform.transform(DiseaseHistoryTransform.java:60)at com.jzd.health.archive.biz.service.transform.DiseaseHistoryTransform.transform(DiseaseHistoryTransform.java:21)at com.jzd.frw.common.transformer.AbstractContextualObjectTransformer.transform(AbstractContextualObjectTransformer.java:26)at com.jzd.frw.common.tr

定位到这里,也就是set这样代码报的NPE。这里的chronicDiseaseFlag是Boolean。

if (CollectionsUtils.isNotEmpty(diseaseInfoDTOS)) {dto.setChronicDiseaseFlag(diseaseInfoDTOS.get(0) == null ? false : diseaseInfoDTOS.get(0).getChronicDiseaseFlag());}

二、原因:三目运算符表达式类型对齐拆箱导致NPE

这里怎么会有NPE?卡克10分钟…吃完饭才想通很久很久以前,一位同事来问过我类似的问题,也是三目运算符中出现的NPE。直觉告诉我,一定是代码问题,而不是什么“诡异”的问题。

结论:
三目运算符左右表达式在类型对齐时,产生了自动拆箱的操作,导致NPE。也就是说:

diseaseInfoDTOS.get(0)当然不为NULL,但是diseaseInfoDTOS.get(0).getChronicDiseaseFlag()为NULL,因为chronicDiseaseFlag本来就是包装类Boolean,所以赋值为NULL没任何问题。But!在三目运算符中,它自己做了“类型对齐”,这里因为表达式1是false,所以会尝试跟它对齐,把NULL转成基本类型的boolean值,自然就报错喽。

更加详细全面的解释如下文:

答案在这里:

https://mp.weixin.qq.com/s/iQ6qdNv7WTLa3drxNa9png

摘抄下最核心的2句话。

三目运算符condition ?表达式1:表达式2中,高度注意表达式1和2再类型对齐时,可能跑出因自动拆箱导致的NPE异常。
说明:以下两种场景会出发类型对齐的拆箱操作。1)表达式1或表达式2的值只要有一个是原始类型;(俺的示例就符合这一条)2)表达式1或表达式2的值的类型不一致,会强制拆箱升级成表示范围更大的那个类型。(俺的示例也符合这一条)

2)能说明三目再背后会把boolean向上转型成Boolean。是的boolean-> Boolean没事;但是null -> Boolean就有事了。

三、继续深究

如果不是网上搜搜,自己能通过判断找到为啥这里会出现问题呢?自己不就是死活想不通这里这么会出现NPE,然后就在原地打转?没有进展。可见,排查问题思路不够开阔。

怎么证明三目自动拆箱了呢?反编译。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wwgj4KJ4-1591626663104)(http://note.youdao.com/yws/res/93973/9E4A2AF2766D469BB3B671EC5D2DCFD4)]

发现这样行不通,就用命令行看下

[@ddeMacBook-Air:transform (develop)]$ javac TestTernaryOperatorNPE.java
[@dzjdeMacBook-Air:transform (develop)]$ ls
DiseaseHistoryTransform.java                   TestTernaryOperatorNPE$DiseaseInfoDTO.class    TestTernaryOperatorNPE.java
TestTernaryOperatorNPE$DiseaseHistoryDTO.class TestTernaryOperatorNPE.class
[@dzjdeMacBook-Air:transform (develop)]$ javap -c TestTernaryOperatorNPE.class
Compiled from "TestTernaryOperatorNPE.java"
public class com.dzj.health.archive.biz.service.transform.TestTernaryOperatorNPE {public .health.archive.biz.service.transform.TestTernaryOperatorNPE();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: new           #2                  // class com//health/archive/biz/service/transform/TestTernaryOperatorNPE$DiseaseHistoryDTO3: dup4: invokespecial #3                  // Method com//health/archive/biz/service/transform/TestTernaryOperatorNPE$DiseaseHistoryDTO."<init>":()V7: astore_18: invokestatic  #4                  // Method java/util/Collections.emptyList:()Ljava/util/List;11: astore_212: aload_213: invokeinterface #5,  1            // InterfaceMethod java/util/List.size:()I18: iconst_119: if_icmplt     5922: aload_123: aload_224: iconst_025: invokeinterface #6,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;30: ifnonnull     3733: iconst_034: goto          5337: aload_238: iconst_039: invokeinterface #6,  2            // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;44: checkcast     #7                  // class com/dzj/health/archive/biz/service/transform/TestTernaryOperatorNPE$DiseaseInfoDTO47: invokevirtual #8                  // Method com/dzj/health/archive/biz/service/transform/TestTernaryOperatorNPE$DiseaseInfoDTO.getChronicDiseaseFlag:()Ljava/lang/Boolean;50: invokevirtual #9                  // Method java/lang/Boolean.booleanValue:()Z53: invokestatic  #10                 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;56: invokevirtual #11                 // Method com/dzj/health/archive/biz/service/transform/TestTernaryOperatorNPE$DiseaseHistoryDTO.setChronicDiseaseFlag:(Ljava/lang/Boolean;)V59: return
}

也看不出啥名堂。

四、总结

1) 如果报错,一定是代码问题,不要觉得“诡异”,只是自己受知识面限制,想不到罢了;

2)学会利用编译和反编译查找问题。

最后,啰嗦几句。

曾几何时,特别害怕NPE,因为那时候开发一个功能,总是出现好多好多NPE,修复一个刚部署好,又接着一个,然后又接着一个…
修到让人崩溃。当然,这只能说明什么,那时候真“菜”。

后来不怕NPE了,修NPE很简单,但是找到引发NPE的原因需要花点心思,比如userId在不应该出现NUll的情况下出现了NULL,这个时候不仅只是修复问题,要寻找到根源。

再后来,算这次,遇到过2次三目运算符导致的NPE。怎么都想不通这儿怎么会是NPE!为了避免第三次碰到,这里必须总结下。

三目运算符引起的NPE相关推荐

  1. Java三目运算符导致 NPE

    在三目运算符中,表达式 1 和 2 在涉及算术计算或数据类型转换时,会触发自动拆箱.当其中的操作数为 null 值时,会导致 NPE . 一.基础知识 三目运算符 三目运算符是 Java 语言中的重要 ...

  2. 【Java后端】三目运算符失效问题刨根问底(及NPE分析)

    我的开发问题记录里有这么一个问题,当时项目着急就没用三目,也没查找原因,那时的bean.getCounter()返回值也不知道是啥了,没有关系,咱们彻底分析一下这个问题. // 三目失效 String ...

  3. java类用三木运算编译不生效_Java 中的三目运算符使用不当所导致的问题

    Java 中的三目运算符使用不当所导致的问题 写在前面: 1.三目运算符是我们经常在代码中使用的,a= (b==null?0:1); 这样一行代 码可以代替一个 if-else,可以使代码变得清爽易读 ...

  4. Java中的三目运算符可能出现的问题

    你真的了解Java中的三目运算符吗? 原创 2018-04-27 刨根问底的 Hollis Hollis Hollis 微信号 hollischuang 功能介绍 一个对Coding有着独特追求的人. ...

  5. 三目运算符_Java中的三目运算符

    某日,同事给我展示了一块代码,问我有没有什么问题.(代码如下 代码块1): int i = 1; Boolean a = null; boolean b = false; System.out.pri ...

  6. 你真的了解Java中的三目运算符吗

    转载自 你真的了解Java中的三目运算符吗 三目运算符是我们经常在代码中使用的,a= (b==null?0:1);这样一行代码可以代替一个if-else,可以使代码变得清爽易读. 但是,三目运算符也是 ...

  7. [转载] 你真的会用 Java 中的三目运算符吗

    参考链接: Java中的按位运算符 转载:http://blog.jobbole.com/93511/ 写在前面: 三目运算符是我们经常在代码中使用的,a= (b==null?0:1); 这样一行代码 ...

  8. 《新版阿里巴巴Java开发手册》提到的三目运算符的空指针问题到底是个怎么回事?

    最近,阿里巴巴Java开发手册发布了最新版--泰山版,这个名字起的不错,一览众山小. 新版新增了30+规约,其中有一条规约引起了作者的关注,那就是手册中提到在三目运算符使用过程中,需要注意自动拆箱导致 ...

  9. 5年前我在博客中写的三目运算符的空指针问题,终于被阿里巴巴开发手册收录了。...

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 267篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) 最近,阿里巴巴Java ...

最新文章

  1. Mask R-CNN 源代码终上线,Facebook 开源目标检测平台—Detectron
  2. Vue2.0 + ElementUI 手写权限管理系统后台模板(一)——简述
  3. 哈希表的C实现(三)---传说中的暴雪版
  4. androidx使用FileProvider适配安卓7
  5. libevent(1)
  6. CentOS 6.5 初始值
  7. CSS 基础框盒模型介绍
  8. [翻译] DoImagePickerController
  9. python两个数组合并、找出中位数_leetcode刷题记录-找出这两个有序数组的中位数(python版本)...
  10. 简单树匹配算法STM-理论篇
  11. vue从入门到进阶:Class 与 Style 绑定(四)
  12. 2017-2018-1 20155322 20155327 实验一 开发环境的熟悉
  13. win7仿win8主题
  14. 这10个比较好用的服务器管理软件你都知道吗?
  15. 经验模态分解python_EMD经验模态分解
  16. 【软件测试】你最常用的web测试-浏览器兼容性测试
  17. visual studio 总是和搜狗输入法冲突
  18. Antd Form Upload 报fileList错误-解决方案
  19. 云计算概念简述(讲解)
  20. 自然语言处理是什么?学习自然语言处理(NLP)

热门文章

  1. 读书笔记-深度学习推荐系统1-概述章节
  2. (五)VxWorks7之wind River Workbench4远程连接调试程序
  3. centos下所有命令都不能用
  4. C语言之fileno函数
  5. 小程序用户收货地址修改
  6. 在win8.1上用3proxy搭建socks4/4.5/5代理
  7. Web结构挖掘算法概述
  8. mysql定时任务每天凌晨三点钟醒来_LINUX 配置定时任务,每天凌晨1点定时备份数据库...
  9. 根据显卡型号选择CUDA和cuDNN进行TensorFlow GPU版本安装
  10. 自己的一项发明专利已获国家知识产权局授权,另外在数据挖掘、海量数据处理领域的两项发明专利已启动申报