Java三目运算符导致 NPE

news2024/12/29 1:44:59

在三目运算符中,表达式 1 和 2 在涉及算术计算或数据类型转换时,会触发自动拆箱。当其中的操作数为 null 值时,会导致 NPE 。

一、基础知识

三目运算符

三目运算符是 Java 语言中的重要组成部分,它也是唯一有 3 个操作数的运算符。形式为:

<表达式1> ? <表达式2> : <表达式3>

以上,通过 ?、:  组合的形式得到一个条件表达式。其中 ? 运算符的含义是:先求表达式 1 的值,如果为真,则执行并返回表达式 2 的结果;如果表达式 1 的值为假,则执行并返回表达式 3 的结果。 

自动装箱与自动拆箱

Java自动拆箱空指针异常

二、问题重现

如下代码在执行是会抛出空指针异常

        Double a = null;
        Integer b = null;
        Double c = Objects.nonNull(b) ? b : a;

异常:

三、原理

以上代码反编译出字节码如下:

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: aconst_null
         1: astore_1
         2: aconst_null
         3: astore_2
         4: aload_2
         5: invokestatic  #2                  // Method java/util/Objects.nonNull:(Ljava/lang/Object;)Z
         8: ifeq          19
        11: aload_2
        12: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
        15: i2d
        16: goto          23
        19: aload_1
        20: invokevirtual #4                  // Method java/lang/Double.doubleValue:()D
        23: invokestatic  #5                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
        26: astore_3
        27: return

  #12行可以看出b Integer类型变量开箱为int值,#20行可以看出a Double变量开箱为double值,#23行可以看出将根据条件,得出的double/int值装箱为Double类型的对象。翻译成java代码如下:

 Double c = Double.valueOf(Objects.nonNull(b) ? b.intValue() : a.doubleValue());

b,a都是null值,因此调用函数时报出npe异常。

分析之后我们可以得出这样的结论:三目运算符和自动拆箱导致了空指针异常。

那么,为什么编译器会进行自动拆箱呢?什么情况下需要进行自动拆箱呢?这其实是三目运算符的语法规范。参见jls-15.25,摘要如下:

 

以去翻阅一下。

其实简单总结下,就是:

1)如果第二个和第三个操作数具有相同的类型(可能是null类型),那么这就是条件表达式的类型。

2)如果第二个和第三个操作数中的一个是基本类型T,而另一个操作数的类型是对T应用装箱转换(§5.1.7)的结果,则条件表达式的类型为T。

3)如果第二个和第三个操作数中的一个是空类型,而另一个操作数的类型是引用类型,则条件表达式的类型就是该引用类型。

否则,如果第二个和第三个操作数的类型可转换为数值类型(§5.1.8),则有以下几种情况:

1)如果一个操作数是byte或Byte类型,另一个是short或Short类型,则条件表达式的类型为short。

2)如果其中一个操作数是T类型,其中T是byte、short或char,而另一个操作数是int类型的常量表达式(§15.28),其值可以用T类型表示,则条件表达式的类型为T。

3)如果其中一个操作数是T类型,其中T是字节、短或字符,而另一个操作数是int类型的常量表达式(§15.28),其值可以用U类型表示,U是对T应用开箱转换的结果,那么条件表达式的类型是U。

否则,二进制数值提升(§5.6.2)应用于操作数类型,条件表达式的类型是第二个和第三个操作数的提升类型。注意,二进制数字提升执行值集转换(§5.1.13),并可能执行开箱转换(§5.1.8)。

值集转换规则:

当操作符对一对操作数应用二进制数字提升,每个操作数必须表示一个可转换为数字类型的值时,应用以下规则,顺序:

1)如果任何操作数是引用类型,它将进行开箱转换(§5.1.8)。

2)扩展基元转换(§5.1.2)应用于按以下规则指定的任意一个或两个操作数转换:

  • 如果其中一个操作数为double类型,则另一个操作数转换为double类型。
  • 否则,如果其中一个操作数为float类型,则另一个操作数转换为float类型。
  • 否则,如果其中一个操作数为long类型,则另一个操作数转换为long类型。
  • 否则,两个操作数都转换为int类型。

我自己的话总结一下,npe其实是值集转换引起的,当以下操作符不能自然转换时(比如一个值为byte,一个值为short,可以),会产生值集转换,而根据值集转换规则1),任何引用类型都要开箱,那么空值开箱就会导致NPE。

最根的解决方法就是阿里巴巴新出的规范:

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

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

相关文章

Linux常用命令——tempfile命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tempfile shell中给临时文件命名 补充说明 有时候在写Shell脚本的时候需要一些临时存储数据的才做&#xff0c;最适合存储临时文件数据的位置就是/tmp&#xff0c;因为该目录中所有的内容在系统重启后就会被清…

LInux(三)程序地址空间、内存管理

目录 一、程序地址空间 二、内存管理方式 1、分段式内存管理 2、分页式内存管理 3、段页式内存管理 三、关于内存管理内容补充&#xff08;分页式&#xff09; 1、页表简单呈现 2、访问权限位 3、缺页中断 4.内存置换算法 一、程序地址空间 创建父子进程同时访问同一变量…

正式发布丨Azure OpenAI Service

Azure OpenAI 服务现已在微软全球 Azure 平台正式发布&#xff0c;这是微软人工智能大众化以及与 OpenAI 持续合作的又一里程碑。 大型语言模型正迅速成为用户无限创新、应用 AI 解决重要问题的平台。随着 Azure OpenAI 服务的正式发布&#xff0c;更多企业用户可以访问世界先…

在线支付系列【5】支付安全之数字证书

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 文章目录公钥信任问题数字证书颁发流程使用流程SSL数字证书HTTPSSSL/TLS 证书如何申请SSL 证书使用keytool 生成ssl证书通信过程公钥信任问题 之前我们使用对称、非对称加密、信息摘要、数字签名&#…

DPDK系列之一基础环境搭建

一、DPDK是什么 DPDK,Data Plane Development Kit&#xff0c;数据平面开发套装&#xff0c;它还有一个兄弟SPDK&#xff0c;专门用来做存储优化的。它主要运行于Linux&#xff0c;是由Intel几家公司共同开发&#xff0c;用于快速处理数据的一个网络开发工具套装。更详细的说明…

python数据清洗1

数据获取——》数据清洗——》数据转换——》数据分析 通过设置步长&#xff0c;有间隔的取元素通过设置步长为-1&#xff0c;将元素颠倒 数据清洗工具 目前在Python中, numpy和pandas是最主流的工具。 Numpy中的向量化运算使得数据处理变得高效&#xff1b;Pandas提供了大量…

【Java入门】Java数据类型

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;Java入门 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又一…

(十四)线程池

线程池线程池是一组线程的集合。线程池维护一个队列&#xff0c;调用者向这个队列中添加任务&#xff0c;而线程池中的线程则不停地从队列中取出任务执行。线程池的继承关系如下图&#xff0c;其中ThreadPoolExecutor和ScheduledThreadPoolExecutor是具体的实现。ThreadPoolExe…

LeetCode刷题模版:141 - 150

目录 简介141. 环形链表142. 环形链表 II143. 重排链表144. 二叉树的前序遍历145. 二叉树的后序遍历146. LRU 缓存【未实现】147. 对链表进行插入排序148. 排序链表149. 直线上最多的点数150. 逆波兰表达式求值结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方…

多轮对话(三):Spoken Language Understanding 进展和前沿

本篇博客基于哈工大发表在IJCAI上的论文&#xff1a;A Survey on Spoken Language Understanding - Recent Advances and New Frontiers。 论文链接 github链接 口语理解&#xff08;SLU&#xff09;旨在提取用户查询的语义框架&#xff0c;是面向任务的对话系统的核心组件。本…

excel函数技巧:两个查询函数的用法比较 上篇

EXCEL函数江湖烽烟再起&#xff0c;函数大擂台迎来两位重量级选手。守擂者是号称全民偶像、人见人爱车见车载的巨星级函数VLOOKUP&#xff0c;挑战者则是名气不大实力强劲高手的LOOKUP函数&#xff01;这对与生俱来的对手&#xff0c;究竟会在函数擂台上擦出怎样的火花&#xf…

Nginx原理

一、master和worker二、worker当客户端发送请求&#xff0c;先到达master,master通知所有的worker,然后所有的worker开始竞争任务。三、一个master和多个worker有什么好处&#xff08;1&#xff09;可以使用nginx -s reload热部署&#xff0c;利用nginx进行热部署&#xff08;2…

8、MariaDB11数据库安装初始化密码Navicat连接

MariaDB11安装 安装前准备 下载安装包 点我去MariaDB官网下载安装包 查看相关文档 Mariadb Server官方文档 使用zip安装 解压缩zip 将下载到的zip解压缩到想安装的位置。 生成data目录 打开cmd并进入到刚才解压后的bin目录&#xff0c; 执行mysql_install_db.exe程序生…

Python异步编程Future对象详解

今天继续给大家介绍Python相关知识&#xff0c;本文主要内容是Python异步编程Future对象详解。 一、Python Future对象简介 在上文Python Task对象详解中&#xff0c;我们介绍到了Task对象&#xff0c;而Future对象是Task对象的基类&#xff0c;比Task更加底层。一个Future是…

英方软件在科创板上市:总市值89亿元,胡军擎、江俊夫妇为实控人

1月19日&#xff0c;上海英方软件股份有限公司&#xff08;下称“英方软件”&#xff0c;SH:688435&#xff09;在上海证券交易所科创板上市。本次上市&#xff0c;英方软件的发行价为38.66元/股&#xff0c;发行2094.6737万股&#xff0c;募资总额约为8.10亿元&#xff0c;募资…

linux的工具(yum,vim)

前言 linux工具的意义Linux已经成为工作、娱乐和个人生活等多个领域的支柱&#xff0c;人们已经越来越离不开它。在 Linux 的帮助下&#xff0c;技术的变革速度超出了人们的想象&#xff0c;Linux 开发的速度也以指数规模增长。因此&#xff0c;越来越多的开发者也不断地加入开…

pycharm远程链接服务器配置

拿到gpu的节点以后开始下面的配置 1. 下载专业版pycharm&#xff0c;一定是专业版&#xff0c;community版本没有远程连接ssh的功能。 2. python编译器->添加ssh编译器->新创建服务器配置 3. 输入host名&#xff0c;用户名。 host名字如&#xff1a;vpcc-gpu032&#xf…

【自学Docker】Docker wait命令

Docker wait命令 大纲 docker wait教程 docker wait 命令可以用于阻塞一个或多个 Docker容器 直到容器停止&#xff0c;然后打印退出代码。 docker wait命令后面的 CONTAINER 可以是容器Id&#xff0c;或者是容器名。 docker wait语法 haicoder(www.haicoder.net)# docker…

基于蒙特卡洛随机潮流研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

代码审计-8 ThinkPHP框架代码审计 2

文章目录熟悉网站结构确定网站的路由1.通过分析url直接得出路由2.查看app/route.php了解参数过滤情况SQL注入举例任意文件下载与删除任意文件下载代码分析任意文件删除代码分析熟悉网站结构 首先对系统的功能点进行大致的了解&#xff0c;对系统的目录情况进行大致了解&#x…