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

文章目录

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

问题背景

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

	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协议进行许可。转载请署名作者且注明文章出处。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】文件操作重点内容梳理

本文目录 1. 什么是文件 1.1 程序文件 1.2 数据文件 1.3 文件名 2. 文件的打开和关闭 2.1 文件指针 2.2 文件的打开和关闭 3. 文件的顺序读写 3.1 顺序读写函数介绍 4. 文件的随机读写 4.1 fseek 4.2 ftell 4.3 rewind 5. 文本文件和二进制文件 6. 文件读取结束的判定 6.1 被错…

Bert经典变体学习

ALBert ALBERT就是为了解决模型参数量大以及训练时间过长的问题。ALBERT最小的参数只有十几M, 效果要比BERT低1-2个点&#xff0c;最大的xxlarge也就200多M。可以看到在模型参数量上减少的还是非常明显的&#xff0c;但是在速度上似乎没有那么明显。最大的问题就是这种方式其实…

uniapp:手写签名,多张图合成一张图

要实现的内容&#xff1a;手写签名&#xff0c;协议内容。点击提交后&#xff1a;生成1张图片&#xff0c;有协议内容和签署日期和签署人。 实现的效果图如下&#xff1a; 1、签名页面 <template><view class"index"><u-navbar title"电子协议…

《MySQL》第十二篇 数据类型

目录 一. 整数类型二. 浮点类型三. 日期和时间类型四. 字符串类型五. 枚举值类型六. 二进制类型七. 小结 MySQL 支持多种数据类型&#xff0c;学习好数据类型&#xff0c;才能更好的学习 MySQL 表的设计&#xff0c;让表的设计更加合理。 一. 整数类型 类型大小SIGNED(有符号)…

7D透明屏的市场应用广泛,在智能家居中有哪些应用表现?

7D透明屏是一种新型的显示技术&#xff0c;它能够实现透明度高达70%以上的显示效果。这种屏幕可以应用于各种领域&#xff0c;如商业广告、展览展示、智能家居等&#xff0c;具有广阔的市场前景。 7D透明屏的工作原理是利用光学投影技术&#xff0c;将图像通过透明屏幕投射出来…

国产化 | 走近人大金仓-KingbaseES数据库

引入 事务隔离级别 || KingbaseES数据库 开篇 1、KingbaseES数据库 百度百科&#xff1a;金仓数据库的最新版本为KingbaseES V8&#xff0c; KingbaseES V8在系统的可靠性、可用性、性能和兼容性等方面进行了重大改进&#xff0c;支持多种操作系统和硬件平台支持Unix、Linux…

基于罪名法务智能知识图谱(含码源):基于280万罪名预测、20W法务问答与法律资讯问答功能

项目设计集合&#xff08;人工智能方向&#xff09;&#xff1a;助力新人快速实战掌握技能、自主完成项目设计升级&#xff0c;提升自身的硬实力&#xff08;不仅限NLP、知识图谱、计算机视觉等领域&#xff09;&#xff1a;汇总有意义的项目设计集合&#xff0c;助力新人快速实…

ThinkPHP8知识详解:给PHP8和MySQL8添加到环境变量

在PHPenv安装的时候&#xff0c;环境变量默认的PHP版本是7.4的&#xff0c;MySQL的版本是5.7的&#xff0c;要想使用ThinkPHP8来开发&#xff0c;就必须修改环境变量&#xff0c;本文就详细讲解了如果修改PHP和MySQL的环境变量。 1、添加网站 启动phpenv&#xff0c;网站&…

019 - STM32学习笔记 - Fatfs文件系统(一) - FatFs文件系统初识

019 - STM32学习笔记 - Fatfs文件系统&#xff08;一&#xff09; - FatFs文件系统初识 最近工作比较忙&#xff0c;没时间摸鱼学习&#xff0c;抽空学点就整理一点笔记。 1、文件系统 在之前学习Flash的时候&#xff0c;可以调用SPI_FLASH_BufferWrite函数&#xff0c;将数…

四步从菜鸟到高手,Python编程真的很简单(送书第一期:文末送书2本)

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支持&#xff0c;我…

临床医学怎样翻译比较 好

近年来&#xff0c;随着不同国家之间医药行业形成的共同研究趋势&#xff0c;临床翻译对于来自不同国家的医疗人员的合作至关重要。那么&#xff0c;临床医学怎样翻译比较 好&#xff0c;北京哪个翻译公司比较专业&#xff1f; 据了解&#xff0c;临床医学翻译包含患者病历记录…

Linux之 Vim 搜索方式

方式一&#xff1a;快速搜索&#xff08;字符串完全匹配&#xff0c;区分大小写&#xff09; 格式&#xff1a; / 关键词 or &#xff1f; 关键词 /内容 #按回车键搜索 从上到下查找 ?内容 #按回车键搜索 从下到上查找 优点&#xff1a;快速定位到该关键字 回车之后&…

【Lua学习笔记】Lua进阶——Require,三目运算

文章目录 Require短路判断实现三目运算符 Require 这是文件aaa.lua的内容 aaa.lua: a 10 local b 20 print("我是aaa")这是文件example.lua的内容 example.lua: a 100 print(a) require("aaa") --require调用其他脚本文件 print(a) print(b) print(&…

Psim 2022仿真软件的安装--Psim电力仿真实战教程

文章目录 Psim 2022 仿真软件安装及使用教程软件介绍1.下载psim 2022安装软件&#xff0c;有需要的亲请联系作者。2.点击安装文件3.点击进行安装&#xff1a;4.安装完成&#xff0c;打开软件&#xff0c;开始仿真5.仿真模型介绍5.1.单相全控整流电路仿真5.2 三相PFC可控整流电路…

【点选验证码】生成点选验证码图片

生成点选验证码图片 参考博客&#xff1a;https://blog.csdn.net/sinat_39629323/article/details/121989609 from tqdm import tqdm from PIL import Image, ImageDraw, ImageFont, ImageOps import shutil,os import numpy as np import cv2 import math import random fil…

Mysql的增删改查

一.增加数据&#xff08;insert&#xff09; insert into 表名&#xff08;列名1&#xff0c;列名2&#xff0c;列名3&#xff0c;.....列名n&#xff09;values(值&#xff0c;值&#xff0c;值&#xff0c;....值&#xff09; insert into userinfo(id,name,age) values(&quo…

CSS3 实现边框圆角渐变色渐变文字效果

.boder-txt {width: 80px;height: 30px; line-height: 30px;padding: 5px;text-align: center;border-radius: 10px;border: 6rpx solid transparent;background-clip: padding-box, border-box;background-origin: padding-box, border-box;/*第一个linear-gradient表示内填充…

二级制部署kubernetes(1.20)

&#x1f618;作者简介&#xff1a;一名运维工作人员。 &#x1f44a;宣言&#xff1a;人生就是B&#xff08;birth&#xff09;和D&#xff08;death&#xff09;之间的C&#xff08;choise&#xff09;&#xff0c;做好每一个选择。 &#x1f64f;创作不易&#xff0c;动动小…

RISC-V公测平台发布 · 第一个WEB Server “Hello RISC-V world!”

RISC-V公测平台Web Server地址&#xff1a;http://175.8.161.253:8081 一、前言 Web Server是互联网应用的基础设施&#xff0c;无论是用户访问网站&#xff0c;还是后端服务提供商和开发者构建各种应用程序&#xff0c;Web Server都在其中扮演着至关重要的角色。 显而易见…

服务器 Docker Alist挂载到本地磁盘(Mac版)夸克网盘

1.服务器下载alist 默认有docker环境 docker pull xhofe/alist2.生成容器 -v /home/alist:/opt/alist/data 这段意思是alist中的数据映射到docker 主机的文件夹&#xff0c;/home/alist就是我主机的文件夹&#xff0c;这个文件夹必须先创建 docker run -d --restartalways…