当前位置: 首页 > news >正文

002. java.lang.NumberFormatException: Infinite or NaN,怎么破?

在这里插入图片描述
你好,我是YourBatman:当我老了,也写代码;不为别的,只为爱好。

📚前言

如果你工作超5年,100%遇到过这个异常:java.lang.NumberFormatException: Infinite or NaN
在这里插入图片描述

  • Infinite中文释义:极大的、无法衡量的、无穷尽的;
  • NaN:Not a Number,不是一个数,它是计算机科学中数据类型的一种,代表不可表示的值,常用于浮点数计算中,于1985年纳入浮点数标准IEEE 754。

在 Java 中只有浮点类型(Float&Double)实现了IEEE 754标准

它还有些变种异常:阅完本文就知道这些异常本质上其实是一回事了

  • java.lang.NumberFormatException: For input string: NaN
  • java.sql.SQLException: 'NaN' is not a valid numeric or approximate numeric value

✍正文

java.lang.NumberFormatException: Infinite or NaN异常并不算常见(毕竟开发中浮点数远远没有整数使用场景多),但也绝不罕见。so,知道为何会出现此异常,以及如何解决它是每个开发者必知必会的知识点。

🌈异常哪里抛出来的?

(假设你看不到异常栈)从抛出的异常中可以提取到两个关键信息供以我们查找异常源头:

  1. 异常类型:java.lang.NumberFormatException
  2. 异常detail msg:Infinite or NaN

首先当然是利用Java语言强类型的优势,看看哪些地方引用到了java.lang.NumberFormatExceptionNumberFormatException
在这里插入图片描述
OMG,在641个地方出现过,看到这个数字该当场死心了:这条信息基本就是无效信息。

无奈再根据关键字Infinite or NaN搜索试试:
在这里插入图片描述
太幸运了,有且仅有一处代码里存在。看看是哪里:
在这里插入图片描述
破案了: java.lang.NumberFormatException: Infinite or NaN异常有且仅在构造BigDecimal实例的时候才有可能抛出。

🌈抛出此异常的原因

既然抛出此异常的源码都找到了,并且还只有一处,回答此问题就非常容易了:

public BigDecimal(double val, MathContext mc) {if (Double.isInfinite(val) || Double.isNaN(val))throw new NumberFormatException("Infinite or NaN");... // 省略其它代码
}

逻辑简单,将Double的两个方法isInfinite()isNaN()一看便知:

public final class Double extends Number implements Comparable<Double> {// 常量public static final double POSITIVE_INFINITY = 1.0 / 0.0;public static final double NEGATIVE_INFINITY = -1.0 / 0.0;public static final double NaN = 0.0d / 0.0;public static boolean isInfinite(double v) {return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);}public static boolean isNaN(double v) {return (v != v);}}

一个个来。

🚀isInfinite(double v)

public static final double POSITIVE_INFINITY = 1.0 / 0.0;
public static final double NEGATIVE_INFINITY = -1.0 / 0.0;public static boolean isInfinite(double v) {return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
}

将v和两个常量比较而已,逻辑不可谓不简单。那么关键点来了:什么情况下一个double类型的值会和POSITIVE_INFINITY/NEGATIVE_INFINITY常量相等呢?

其实看Double类对这两个常量的定义,就明白了(参考👆🏻常量定义代码)。为了更清晰的对号入座,笔者这里再来几个举一反三的case:

@Test
public void fun2() {// 等于Double.POSITIVE_INFINITY的场景System.out.println(1.0 / 0 == Double.POSITIVE_INFINITY); // trueSystem.out.println(2.0 / 0 == Double.POSITIVE_INFINITY); // trueSystem.out.println(1 / 0.0 == Double.POSITIVE_INFINITY); // trueSystem.out.println(2 / 0.0 == Double.POSITIVE_INFINITY); // trueSystem.out.println(new Double(Double.POSITIVE_INFINITY) == Double.POSITIVE_INFINITY); // true// 等于Double.NEGATIVE_INFINITY的场景System.out.println(-1.0 / 0 == Double.NEGATIVE_INFINITY); // trueSystem.out.println(-2.0 / 0 == Double.NEGATIVE_INFINITY); // trueSystem.out.println(-1 / 0.0 == Double.NEGATIVE_INFINITY); // trueSystem.out.println(-2 / 0.0 == Double.NEGATIVE_INFINITY); // trueSystem.out.println(new Double(Double.NEGATIVE_INFINITY) == Double.NEGATIVE_INFINITY); // true// 需特别注意的特殊case:System.out.println(1.0 / -0 == Double.POSITIVE_INFINITY); // -0和0没有区别,所以结果是POSITIVE(true)System.out.println(1.0 / -0.0 == Double.NEGATIVE_INFINITY); // -0.0和0.0是有区别的,所以结果是POSITIVE(false)
}

总结一下:浮点数除法运算,分母为0且分子不为0,结果就是POSITIVE_INFINITY/NEGATIVE_INFINITY。

Tips:它哥两分别称作正无穷大负无穷大

🚀isNaN(double v)

public static final double NaN = 0.0d / 0.0;public static boolean isNaN(double v) {return (v != v);
}

what?自己还能不等于自己?bug吧~

来看看:

@Test
public void fun3() {// double d = 0.0d / 0; // 结果一样System.out.println(d == Double.NaN);System.out.println(Double.isNaN(d));
}

运行后的输出结果为:

false
false -> d==d这个是falsetrue

惊不惊喜,意不意外:还真存在自己不等于自己的情况呢。

总结一下:浮点数除法计算,分母为0且分子为0,结果就是NaN。并且:每次计算的NaN都永不相等。

Tips:NaN代表不是数字,因此“不是数字”和“不是数字”不相等,从逻辑上好像也说得通嘛

🌈针对此异常的补充说明

围绕POSITIVE_INFINITY、NEGATIVE_INFINITY、NaN三个常量进行一些补充说明吧。

🚀直接打印输出什么?

@Test
public void fun4() {System.out.println(Double.POSITIVE_INFINITY);System.out.println(Double.NEGATIVE_INFINITY);System.out.println(Double.NaN);
}

运行程序,输出:

Infinity
-Infinity
NaN

总结一下:Double对象打印输出(toString或者序列化),不一定永远是数字,也有可能是字符串。

🚀 是否可以参与运算和比较?

虽然是常量,但毕竟也是数字类型嘛,那就看看运算和比较喽:

运算

@Test
public void fun7() {System.out.println("正无穷大参与运算:" + (Double.POSITIVE_INFINITY + 1)); // InfinitySystem.out.println("正无穷大参与运算:" + (Double.POSITIVE_INFINITY - 1)); // InfinitySystem.out.println("负无穷大参与运算:" + (Double.NEGATIVE_INFINITY * 1)); // -InfinitySystem.out.println("负无穷大参与运算:" + (Double.NEGATIVE_INFINITY / 1)); // -InfinitySystem.out.println("负无穷大参与运算:" + (Double.NEGATIVE_INFINITY / 0)); // -InfinitySystem.out.println("NaN参与运算:" + (Double.NaN + 1)); // NaNSystem.out.println("NaN参与运算:" + (Double.NaN - 1)); // NaNSystem.out.println("NaN参与运算:" + (Double.NaN * 1)); // NaNSystem.out.println("NaN参与运算:" + (Double.NaN / 1)); // NaNSystem.out.println("NaN参与运算:" + (Double.NaN / 0)); // NaN// 特殊场景System.out.println(Double.POSITIVE_INFINITY - Double.POSITIVE_INFINITY); // NaNSystem.out.println(Double.NEGATIVE_INFINITY - Double.NEGATIVE_INFINITY); // NaNSystem.out.println(Double.POSITIVE_INFINITY + Double.NEGATIVE_INFINITY); // NaNSystem.out.println("负无穷大参与运算:" + (Double.POSITIVE_INFINITY / -0.0)); // -InfinitySystem.out.println("负无穷大参与运算:" + (Double.NEGATIVE_INFINITY / -0.0)); // Infinity
}

总结一下:正/负无穷大和任何数值(包括除以0)做运算结果都是本身,和Infinite or NaN运算结果为NaN;NaN进行任何运算的结果都是NaN。

特例:正/负无穷大若除以-0的话,结果互调

比较

@Test
public void fun6() {System.out.println("正无穷大 > 任何数吗? -> " + (Double.POSITIVE_INFINITY > Double.MAX_VALUE)); // trueSystem.out.println("正无穷大 > 任何数吗? -> " + (Double.POSITIVE_INFINITY > Long.MAX_VALUE)); // trueSystem.out.println("负无穷大 < 任何数吗? -> " + (Double.POSITIVE_INFINITY > Double.MIN_VALUE)); // trueSystem.out.println("负无穷大 < 任何数吗? -> " + (Double.POSITIVE_INFINITY > Long.MIN_VALUE)); // trueSystem.out.println("NaN参与比较:" + (Double.NaN == Double.NaN)); // falseSystem.out.println("NaN参与比较:" + (Double.NaN > Double.NaN)); // falseSystem.out.println("NaN参与比较:" + (Double.NaN < Double.NaN)); // falseSystem.out.println("NaN参与比较:" + (Double.NaN < 1)); // falseSystem.out.println("NaN参与比较:" + (Double.NaN < -1)); // falseSystem.out.println("NaN参与比较:" + (Double.NaN != -1)); // trueSystem.out.println("NaN参与比较:" + (Double.NaN != Double.NaN)); // true
}

总结一下:正无穷大比任何数值都大;负无穷大比任何数值都小;NaN参与!=比较永远是true(包括和自己比),除此之外都为false。

🚀 Float里的这三个常量和Double一样吗?

弱弱问一句:2023年了在实际业务开发中,不会真有人使用Float吧?吧?吧?

灵魂拷问:如果你使用了Float,收益是什么?是否真的值得?

Float类里也存在这三个常量和判断的方法:

public final class Float extends Number implements Comparable<Float> {// 常量public static final float POSITIVE_INFINITY = 1.0f / 0.0f;public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;public static final float NaN = 0.0f / 0.0f;public static boolean isInfinite(float v) {return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);}public static boolean isNaN(float v) {return (v != v);}}

和Double可谓一毛一样嘛。看下这个:

@Test
public void fun5() {System.out.println(Double.POSITIVE_INFINITY == Float.POSITIVE_INFINITY);System.out.println(Double.NEGATIVE_INFINITY == Float.NEGATIVE_INFINITY);System.out.println(Double.NaN == Float.NaN);
}

运行程序,输出:

true
true
false

结论无需多言,自行体会做到心中有数哈。

🚀 其它语言的表现

以弱类型语言JavaScript为例:
在这里插入图片描述
表现和Java一样。毕竟NaN早已被纳入IEEE 754规范了,不出意外每种编程语言的表现都是一致的。

Tips:JavaScript中的isFinite()方法是正向思维的,和Java里isInfinite()是“反”着来的哦

🌈遇到此异常怎么破?

解决问题的难度永远在根因定位上,至于遇到此异常怎么破嘛,略!!!

考虑到代码的健壮性,实际场景中是可以对这些异常做预处理的:使用Double.isNaN()Double.isInfinite()等方法来做分支逻辑

🍞总结

在Java中,浮点数0并非一个准确值,而是一个无限接近0的数。为此才闹出这么多令人费解的“幺蛾子”,这是由计算机底层原理决定的,记住就好,无解。

计算机的运算基于数学,但貌似也有些“不同于”数学理论。这不,NaN这玩意就是这么神奇的存在。

推荐阅读

  • 001. 为啥用IDEA反编译没有擦除泛型?

在这里插入图片描述
本专栏源代码库:https://github.com/yourbatman/yourbatman-999-question

  • 个人博客:https://yourbatman.cn
  • 程序员网盘:https://wangpan.yourbatman.cn
  • 女娲工程:https://start.yourbatman.cn
  • 更多专栏:https://yourbatman.cn/columns |或| 公号后台回复“专栏列表”获取全部小而美的原创技术专栏

我是YourBatman,一个俗人,贪财好色。历经过延期毕业、卖保险、送外卖的大龄程序员,《梦幻西游》骨灰玩家;龙珠迷、火影迷。前大厂资深技术专家,现资深领域建模专家、Java架构师;高质量代码、DDD面向对象设计布道师;Spring开源贡献者,CSDN博客之星年度Top 10,出版书籍《Spring奇淫巧技》&《领域建模之面向对象程序设计》进行时。wx:yourbatman-u

相关文章:

002. java.lang.NumberFormatException: Infinite or NaN,怎么破?

你好&#xff0c;我是YourBatman&#xff1a;当我老了&#xff0c;也写代码&#xff1b;不为别的&#xff0c;只为爱好。 &#x1f4da;前言 如果你工作超5年&#xff0c;100%遇到过这个异常&#xff1a;java.lang.NumberFormatException: Infinite or NaN Infinite中文释义…...

Vue常用的修饰符

Vue常用的修饰符有哪些有什么应用场景 修饰符是什么 在Vue中&#xff0c;修饰符处理了许多DOM事件的细节&#xff0c;让我们不再需要花大量的时间去处理这些烦恼的事情&#xff0c;而能有更多的精力专注于程序的逻辑处理 分类、有5种 表单修饰符事件修饰符鼠标按键修饰符键…...

freertos笔记-任务切换

红叶何时落水 任务切换&#xff0c;调用PendSV #define taskYIELD() portYIELD() #define portYIELD() \ { \portNVIC_INT_CTRL_REG portNVIC_PENDSVSET_BIT; \ 通过向中断控制和壮态寄存器 ICSR 的 bit28 写入 1 挂起 PendSV 来启动 PendSV 中断\__dsb( portSY_FULL_READ…...

企业电子招投标采购系统源码之登录页面-java spring cloud

​ 信息数智化招采系统 服务框架&#xff1a;Spring Cloud、Spring Boot2、Mybatis、OAuth2、Security 前端架构&#xff1a;VUE、Uniapp、Layui、Bootstrap、H5、CSS3 涉及技术&#xff1a;Eureka、Config、Zuul、OAuth2、Security、OSS、Turbine、Zipkin、Feign、Monitor、…...

接口测试|Fiddler弱网测试

Fiddler进行弱网测试 弱网测试 概念&#xff1a;弱网看字面意思就是网络比较弱&#xff0c;我们通称为信号差&#xff0c;网速慢。 意义&#xff1a;模拟在地铁、隧道、电梯和车库等场景下使用APP &#xff0c;网络会出现延时、中断和超时等情况。 在这里插入图片描述 Fidd…...

Linux-0.11 文件系统super.c详解

Linux-0.11 文件系统super.c详解 模块简介 该模块主要包含了对超级块的一些读写操作。 函数详解 lock_super static void lock_super(struct super_block * sb)该函数的作用是锁定bh块。 cli();//关中断while (sb->s_lock)//如果已经被锁定sleep_on(&(sb->s_wai…...

什么是ChatGPT、历史发展及应用领域

什么是ChatGPT ChatGPT是一种基于深度学习的自然语言处理技术&#xff0c;它可以生成高质量的自然语言文本&#xff0c;该技术是由OpenAI团队开发&#xff0c;旨在使计算机能够像人类一样理解和产生自然语言。ChatGPT使用了深度神经网络和自然语言处理技术&#xff0c;通过对大…...

Spring的创建与使用

目录 1.创建 Spring 项⽬ 1.1 创建一个 maven 项目 1.2 添加 spring 框架支持(spring-context/spring-beans) 2.将 Bean (对象) 存储到 Spring (容器) 中 2.1 在resources中创建一个spring配置文件 2.2 将 Bean 对象存储到 Spring 当中 2.2.1 创建 Bean 对象 2.2.2 将B…...

抖音Flutter插件的使用

Flutter是一个开源的移动应用程序开发框架&#xff0c;由谷歌开发&#xff0c;支持Android和iOS。随着Flutter的发展和成熟&#xff0c;许多人开始使用它来开发跨平台应用程序。本文将介绍如何使用抖音的Flutter插件&#xff0c;以增强Flutter应用程序的功能。 1. 安装Flutter…...

Debezium报错处理系列之六十八:No resolvable bootstrap urls given in bootstrap.servers

Debezium报错处理系列之六十八:No resolvable bootstrap urls given in bootstrap.servers 一、完整报错二、错误原因三、解决方法Debezium报错处理系列一:The db history topic is missing. Debezium报错处理系列二:Make sure that the same history topic isn‘t shared b…...

Python二级编程:分词去重

一、原题 参考编程模板&#xff0c;完善代码&#xff0c;实现以下功能。‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‪‫ 利用 jieba 库实现中文分词。对分词后的列表进行去重处理&#xff0c;然后将分词结果中字符数大于等于 3 的词语&…...

Android Wifi开发——Wifi锁(十九)

有的时候我们需要 APP 在手机后台运行,但是会遇到手机一旦息屏或者断网,APP 无法正常运行的情况,这是因为手机屏幕关闭之后,并且其他的应用程序没有在使用 Wifi 的时候,系统大概在两分钟之后,会关闭 Wifi,使得 Wifi 处于睡眠状态。而 Wifi 锁 就是 Android 锁屏后 Wifi …...

Nginx的优化与防盗链

目录 一. 隐藏版本号方法一&#xff1a;配置文件隐藏版本号方法二&#xff1a;源代码隐藏版本号 修改用户与组缓存时间日志切割连接超时更改进程数配置网页压缩配置防盗链fpm参数优化 一. 隐藏版本号 可以使用 Fiddler 工具抓取数据包&#xff0c;查看 Nginx版本&#xff0c;也…...

STP协议

目录 STP的基本概念&#xff1a; 桥ID&#xff08;Bridge ID&#xff09;&#xff1a; 根桥&#xff1a; 开销&#xff08;Cost&#xff09;&#xff1a; RPC&#xff08;根路径开销&#xff09;&#xff1a; Port ID&#xff1a; BPDU&#xff1a;&#xff08;网桥协议…...

方法——检查参数的有效性

检查参数的有效性 绝大多数方法和构造方法对于传递给它们的参数都会有某些限制,比如对象引用不能为null,比如必须是正数等.你应该在文档中(或者注释中)清楚地指出所有这些限制,并且在方法体的开头检查参数,并且强制施加这些限制.如果做不到这一点,检测出错误的可能性就很小,即…...

七、Docker仓库之nexus搭建(四)

Nexus简介 使用 Docker 官方的 Registry 创建的仓库面临一些维护问题。比如某些镜像删除以后空间默认是不会回收的&#xff0c;需要一些命令去回收空间然后重启 Registry。在企业中把内部的一些工具包放入 Nexus 中是比较常见的做法&#xff0c;最新版本 Nexus3.x 全面支持 Doc…...

MySQL 锁机制

1.概述 锁是计算机协调多个进程或线程并发访问某一种资源的机制。 在数据库中&#xff0c;除去计算机硬件资源&#xff08;CPU、RAM、I/O等&#xff09;的争用外&#xff0c;数据也是一种供许多用户共享的资源。如何保证并发访问数据的一致性、有效性是所有数据库必须解决的一…...

HACKER KID: 1.0.1实战演练

文章目录 HACKER KID: 1.0.1实战演练一、前期准备1、相关信息 二、信息收集1、端口扫描2、访问网站3、扫描目录4、查看源码5、请求参数6、burpsuite批量请求7、编辑hosts文件8、DNS区域传输9、编辑hosts10、访问网站11、注册账号12、burpsuite抓包13、XML注入14、解密15、登录网…...

Android车载学习笔记1——车载整体系统简介

一、汽车操作系统 汽车操作系统包括安全车载操作系统、智能驾驶操作系统和智能座舱操作系统。 1. 安全车载操作系统 安全车载操作系统主要面向经典车辆控制领域&#xff0c;如动力系统、底盘系统和车身系统等&#xff0c;该类操作系统对实时性和安全性要求极高&#xff0c;生态…...

Apache Doris

Apache Doris教程 1.Doris 简介 1.1 Doris 概述 Apache Doris 由百度大数据部研发&#xff08;之前叫百度 Palo&#xff0c;2018 年贡献到 Apache 社区后&#xff0c; 更名为 Doris &#xff09;&#xff0c;在百度内部&#xff0c;有超过 200 个产品线在使用&#xff0c;…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...