三元运算符引发的自动拆装箱问题

news2024/12/24 0:35:08

文章目录

  • 问题背景
  • 问题排查
  • 排查过程
  • 问题扩展
  • 总结

问题背景

生产环境上出现空指针异常,追踪报错位置得知以下代码报错

	if (isNull(aiGroup)) {
        return null;
    }
	aiGroup.setNum(isNull(param.getNum()) ? aiGroup.getNum() : param.getNum().doubleValue());

问题排查

乍一看,真没有什么问题(当然可能是我经验不足),细看会发现自动装箱导致空指针异常,上边set方法代码可以拆分为两行:

	Double num = isNull(param.getNum()) ? aiGroup.getNum() : param.getNum().doubleValue();
	aiGroup.setNum(num);

声明:属性类型:aiGroup#num类型是Double,param#num类型是BigDecimal

你可以自己单独写一个main方法,自行运行一下。

在这里我直接说出来,以上代码在获取num时,如果isNull()方法为true时,会从aiGroup获取num,但是aiGroup.getNum()的结果是null,理论是你直接给一个包装类型属性设置null是没有问题的,比如aiGroup.setNum(null),这样是正确的。

但是三元运算的时候,如果发现结果类型和表达式中的类型不一致,他会在最外层进行自动装箱,会执行Double.valueOf()的操作,所以会出现空指针的现象:Double.valueOf(null)

反之会出现自动拆箱问题。

排查过程

许多人可能会不明白我是怎么知道为什么会有Double.valueOf(null)这一步,过程很简单,查看Java的字节码就可以看到,想看Java字节码更详细的点可以看:Java字节码介绍。

言归正传,在这里为了简单我又新建了一个简单Main类,使三元运算中表达式的类型不一致,代码如下:


public class Main {
    public static void main(String[] args) {

        SdAiGroup aiGroup = new SdAiGroup();
        // aiGroup#num是Double类型,aiGroup#test是double类型
        Double test = Objects.isNull(aiGroup.getId()) ? aiGroup.getNum() : aiGroup.getTest();
        aiGroup.setAcos(test);
        System.err.println(test);
    }
}

生成class文件,然后执行Javap -c Main.class
结果如下:

Compiled from "Main.java"
public class com.sparkxmedia.xmars.ai.center.service.impl.Main {
  public com.sparkxmedia.xmars.ai.center.service.impl.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup
       3: dup
       4: invokespecial #3                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup."<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.getId:()Ljava/lang/Long;
      12: invokestatic  #5                  // Method java/util/Objects.isNull:(Ljava/lang/Object;)Z
      15: ifeq          25
      18: aload_1
      19: invokevirtual #6                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.getTest:()D
      22: goto          29
      25: aload_1
      26: invokevirtual #6                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.getTest:()D
      29: invokestatic  #7                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      32: astore_2
      33: aload_1
      34: aload_2
      35: invokevirtual #8                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.setAcos:(Ljava/lang/Double;)V
      38: getstatic     #9                  // Field java/lang/System.err:Ljava/io/PrintStream;
      41: aload_2
      42: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      45: return
}

可以看到第29行:Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
将结果执行方法Double.valueOf(null);

反之我们将三元运算中表达式的类型和结果类型一致,代码如下:
将Main方法中三元运算符替换为:Double test = Objects.isNull(aiGroup.getId()) ? aiGroup.getNum() : aiGroup.getNum();
结果如下:

Compiled from "Main.java"
public class com.sparkxmedia.xmars.ai.center.service.impl.Main {
  public com.sparkxmedia.xmars.ai.center.service.impl.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup
       3: dup
       4: invokespecial #3                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup."<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.getId:()Ljava/lang/Long;
      12: invokestatic  #5                  // Method java/util/Objects.isNull:(Ljava/lang/Object;)Z
      15: ifeq          25
      18: aload_1
      19: invokevirtual #6                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.getTest:()D
      22: goto          29
      25: aload_1
      26: invokevirtual #6                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.getTest:()D
      29: invokestatic  #7                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      32: astore_2
      33: aload_1
      34: aload_2
      35: invokevirtual #8                  // Method com/sparkxmedia/xmars/ai/center/model/entity/SdAiGroup.setAcos:(Ljava/lang/Double;)V
      38: getstatic     #9                  // Field java/lang/System.err:Ljava/io/PrintStream;
      41: aload_2
      42: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      45: return
}

发现没有Double.valueOf(null)方法了;

问题扩展

根据以上的自动装箱问题,你可以自己试着写个Main方法,试试自动拆箱问题,
比如
三元运算符引发的自动拆装箱问题 - Java技术债务

总结

最根本的问题就是自动拆装箱导致的问题,而三元运算只是问题的引发,更多的自动拆箱和装箱问题,如果不清楚的话, 可以自行google或者留言。


--------------------------------------------------------------欢迎叨扰此地址---------------------------------------------------------------

本文作者:Java技术债务
原文链接:https://cuizb.top/myblog/article/detail/1690515044
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/826066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1500-2000元预算性价比吉他推荐,雅马哈FG800和VEAZEN费森VZ90怎么选?评测对比哪一款更适合初学者入门选购!

在2000元价位入门进阶吉他圈里&#xff0c;可谓是群雄角逐&#xff0c;Yamaha 雅马哈入门级FG800系列和VEAZEN 费森VZ90系列是一直都很热销的面单吉他型号&#xff0c;初学者想要在其中挑选出一把合适自己的吉他还是有点难度的。 那么&#xff0c;今天就以它们为本期的评测主角…

企业级高负载web服务器-Tomcat小项目

目录 web静态动态页面区别安装java环境安装Tomcat安装Tomcat包到目录查看Tomcat主目录结构查看Tomcat配置目录结构Tomcat管理Tomcat web管理功能 部署jpress应用 web静态动态页面区别 静态页面&#xff1a; 在网站设计中&#xff0c;纯粹HTML格式的网页&#xff08;可以包含图…

后端整理(JVM、Redis、反射)

1. JVM 文章仅为自身笔记 详情查看一篇文章掌握整个JVM&#xff0c;JVM超详细解析&#xff01;&#xff01;&#xff01; 1.1 什么是JVM jvm是Java虚拟机 1.2 Java文件的编译过程 程序员编写代码形成.java文件经过javac编译成.class文件再通过JVM的类加载器进入运行时数据…

MFC、Qt、WPF?该用哪个?

MFC、Qt和WPF都是流行的框架和工具&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序。选择哪个框架取决于你的具体需求和偏好。MFC&#xff08;Microsoft Foundation Class&#xff09;是微软提供的框架&#xff0c;使用C编写&#xff0c;主要用于Windows…

蔚小理新势力互联网造车在CAN FD硬件主框架及后装控制方案开发

在国内&#xff0c;新势力造车影响已经非常之大&#xff0c;整个造车大潮中&#xff0c;新整车企业蔚来汽车、小鹏汽车、理想汽车无一例外选择了CAN FD作为主要的车载通信总线&#xff0c;特斯拉推出了引领汽车EE架构集中化的趋势&#xff0c;即使在车载以太网EE架构快速发展的…

BES 平台 SDK之充电盒与耳塞串口单工通信

本文章是基于BES2700 芯片&#xff0c;其他BESxxx 芯片可做参考&#xff0c;如有不当之处&#xff0c;欢迎评论区留言指出。仅供参考学习用&#xff01; BES 平台 SDK之主从耳组队_谢文浩的博客-CSDN博客 关于系统主从耳组队流程可参考上一篇文章。链接如上所示&#xff01; …

初识集合和背后的数据结构

目录 集合 Java集合框架 数据结构 算法 集合 集合&#xff0c;是用来存放数据的容器。其主要表现为将多个元素置于一个单元中&#xff0c;用于对这些元素进行增删查改。例如&#xff0c;一副扑克牌(一组牌的集合)、一个邮箱(一组邮件的集合&#xff09;。 Java中有很多种集…

捷码低代码|Modal模态框组件详解

知识补充&#xff1a; 模态组件是一种在用户界面中显示的特殊类型的组件。它们被设计为在应用程序的其他部分被屏蔽或暂停的情况下引导用户完成一个特定的任务或交互。 常见的模态组件包括&#xff1a; 1、弹出窗口&#xff08;Popup&#xff09;&#xff1a;弹出窗口是一种常见…

Unity中UGUI的 OnPopulateMesh函数与VertexHelper类

Graphics类 当一个UGUI的UI元素生成顶点数据时会调用Graphics类中的 OnPopulateMesh(VertexHelper vh) 函数&#xff0c;我们可以在这个函数中修改顶点的数据或者获取顶点的数据。 UGUI中与显示相关的控件&#xff0c;例如Image、Text、RawImage等都继承自MaskableGraphic类&a…

正则替换windows文件名禁用的特殊字符

背景&#xff1a; windows文件名中不能出现以下提示的特殊字符&#xff0c;因此需要提前替换处理。 解决&#xff1a; // 替换\/:*?"<>|为空 fileName.replaceAll("[\\\\/:*?\"<>|]", "");

Boost开发指南-3.9object_pool

object_pool object_pool是用于类实例&#xff08;对象&#xff09;的内存池&#xff0c;它的功能与pool类似&#xff0c;但会在析构时对所有已经分配的内存块调用析构函数&#xff0c;从而正确地释放资源。 object_pool位于名字空间boost&#xff0c;为了使用object_pool组件…

千元级入门单板吉他推荐,SAGA萨伽SF700、VEAZEN费森VZ200、布鲁克V12、恩雅X1PRO全方面评测对比,哪一款更值得购买!

很多吉他初学者的预算不多&#xff0c;就想要选购平价又好用的吉他&#xff0c;这个想法是很正确的。初学者要注意的是这种平价且高性价比的吉他需要仔细挑选&#xff0c;太便宜的合板吉他保证不了原材料的品质和制作工艺要求&#xff0c;音准手感都无法保证&#xff0c;那么这…

云主机秘钥泄露及利用

前言&#xff1a; 云平台作为降低企业资源成本的工具&#xff0c;在当今各大公司系统部署场景内已经成为不可或缺的重要组成部分&#xff0c;并且由于各类应用程序需要与其他内外部服务或程序进行通讯而大量使用凭证或密钥&#xff0c;因此在漏洞挖掘过程中经常会遇到一类漏洞&…

时间复杂度、空间复杂度实践练习(力扣OJ)

目录 文章目录 前言 题目一&#xff1a;轮转数组 思路一&#xff1a; 思路二&#xff1a; 思路三&#xff1a; 题目二&#xff1a;消失的数字 思路一&#xff1a; 思路二&#xff1a; 思路三&#xff1a; 题目三&#xff1a;移除元素 思路&#xff1a; 总结 前言 想要编写高效的…

2023年第四届“华数杯”数学建模思路 - 案例:随机森林

## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是随机森林&#xff1f; 随机森林属于 集成学习 中的 Bagging&#xff08;Bootstrap AGgregation 的简称&#xff09; 方法。如果用图来表示他们之…

【技术分享】SSD20X USB摄像头使用

本文主要介绍基于Purple Pi R1演示如何配置USB摄像头&#xff0c;此方法适用于SSD201/202全系列产品。 Purple Pi R1主板&#xff0c;是基于 SigmaStar SSD201 SoC&#xff08;ARM Cortex A7 内核&#xff09;兼容树莓派的开发板&#xff0c;主频高达1.2GHz&#xff0c;256KB …

HR如何提高自己的薪资?或许是一个好选择!

从助理到总监&#xff0c;随着级别的提升&#xff0c;薪资也水涨船高&#xff0c;从4K涨到了24K。值得注意的是&#xff0c;从助理到主管&#xff0c;薪资涨幅较小&#xff0c;而从主管到总监&#xff0c;尤其是经理到总监&#xff0c;薪资有很大的突破。 各行业HR人员薪资水平…

Hutool BeanUtils.copyProperties的四种用法 空不拷贝/忽略拷贝/空不和忽略拷贝/全拷贝

关注公众号&#xff1a;”奇叔码技术“ 回复&#xff1a;“java面试题大全”或者“java面试题” 即可领取资料 一、Hutool BeanUtils.copyProperties的四种用法 空不拷贝/忽略拷贝/空不和忽略拷贝/全拷贝 1、第一种用法&#xff1a; BeanUtils.copyProperties(三个参数) 不为空…

数组指针

数组指针的定义 1.数组指针是指针还是数组&#xff1f; 指针。 int a 10;int* p &a;//指向整型数据的指针 char b w;char* q &b;//指向字符变量的指针 所以数组指针应该是指向数组的指针。 2.数组指针应该怎么定义&#xff1f; int arr[10] { 0 };int(*p)[10] …

【python爬虫】获取某一个网址下面抓取所有的a 超链接下面的内容

import requests as rq from bs4 import BeautifulSoup as bs import re# rooturl是传的是我需要查询和抓取的一个网址&#xff0c;可以是html js 等 def gethtml(rooturl, encoding"utf-8"):#默认解码方式utf-8response rq.get(rooturl)response.encoding encodin…