偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

開發(fā) 前端
在Java中,?浮點數0并非一個準確值,而是一個無限接近0的數。為此才鬧出這么多令人費解的“幺蛾子”,這是由計算機底層原理決定的,記住就好,無解。

你好,我是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異常并不算常見(畢竟開發(fā)中浮點數遠遠沒有整數使用場景多),但也絕不罕見。so,知道為何會出現此異常,以及如何解決它是每個開發(fā)者必知必會的知識點。

??異常哪里拋出來的?

(假設你看不到異常棧)從拋出的異常中可以提取到兩個關鍵信息供以我們查找異常源頭:

  1. 異常類型:java.lang.NumberFormatException
  2. 異常detail msg:Infinite or NaN

首先當然是利用Java語言強類型的優(yōu)勢,看看哪些地方引用到了java.lang.NumberFormatExceptionNumberFormatException:

圖片

OMG,在641個地方出現過,看到這個數字該當場死心了:這條信息基本就是無效信息。

無奈再根據關鍵字Infinite or NaN搜索試試:

圖片

太幸運了,有且僅有一處代碼里存在??纯词悄睦铮?/p>

圖片

破案了:** 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); // true
System.out.println(2.0 / 0 == Double.POSITIVE_INFINITY); // true
System.out.println(1 / 0.0 == Double.POSITIVE_INFINITY); // true
System.out.println(2 / 0.0 == Double.POSITIVE_INFINITY); // true
System.out.println(new Double(Double.POSITIVE_INFINITY) == Double.POSITIVE_INFINITY); // true

// 等于Double.NEGATIVE_INFINITY的場景
System.out.println(-1.0 / 0 == Double.NEGATIVE_INFINITY); // true
System.out.println(-2.0 / 0 == Double.NEGATIVE_INFINITY); // true
System.out.println(-1 / 0.0 == Double.NEGATIVE_INFINITY); // true
System.out.println(-2 / 0.0 == Double.NEGATIVE_INFINITY); // true
System.out.println(new Double(Double.NEGATIVE_INFINITY) == Double.NEGATIVE_INFINITY); // true

// 需特別注意的特殊case:
System.out.println(1.0 / -0 == Double.POSITIVE_INFINITY); // -0和0沒有區(qū)別,所以結果是POSITIVE(true)
System.out.println(1.0 / -0.0 == Double.NEGATIVE_INFINITY); // -0.0和0.0是有區(qū)別的,所以結果是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這個是false喲
true

驚不驚喜,意不意外:還真存在自己不等于自己的情況呢。

總結一下:浮點數除法計算,分母為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)); // Infinity
System.out.println("正無窮大參與運算:" + (Double.POSITIVE_INFINITY - 1)); // Infinity
System.out.println("負無窮大參與運算:" + (Double.NEGATIVE_INFINITY * 1)); // -Infinity
System.out.println("負無窮大參與運算:" + (Double.NEGATIVE_INFINITY / 1)); // -Infinity
System.out.println("負無窮大參與運算:" + (Double.NEGATIVE_INFINITY / 0)); // -Infinity

System.out.println("NaN參與運算:" + (Double.NaN + 1)); // NaN
System.out.println("NaN參與運算:" + (Double.NaN - 1)); // NaN
System.out.println("NaN參與運算:" + (Double.NaN * 1)); // NaN
System.out.println("NaN參與運算:" + (Double.NaN / 1)); // NaN
System.out.println("NaN參與運算:" + (Double.NaN / 0)); // NaN

// 特殊場景
System.out.println(Double.POSITIVE_INFINITY - Double.POSITIVE_INFINITY); // NaN
System.out.println(Double.NEGATIVE_INFINITY - Double.NEGATIVE_INFINITY); // NaN
System.out.println(Double.POSITIVE_INFINITY + Double.NEGATIVE_INFINITY); // NaN

System.out.println("負無窮大參與運算:" + (Double.POSITIVE_INFINITY / -0.0)); // -Infinity
System.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)); // true
System.out.println("正無窮大 > 任何數嗎? -> " + (Double.POSITIVE_INFINITY > Long.MAX_VALUE)); // true
System.out.println("負無窮大 < 任何數嗎? -> " + (Double.POSITIVE_INFINITY > Double.MIN_VALUE)); // true
System.out.println("負無窮大 < 任何數嗎? -> " + (Double.POSITIVE_INFINITY > Long.MIN_VALUE)); // true

System.out.println("NaN參與比較:" + (Double.NaN == Double.NaN)); // false
System.out.println("NaN參與比較:" + (Double.NaN > Double.NaN)); // false
System.out.println("NaN參與比較:" + (Double.NaN < Double.NaN)); // false
System.out.println("NaN參與比較:" + (Double.NaN < 1)); // false
System.out.println("NaN參與比較:" + (Double.NaN < -1)); // false

System.out.println("NaN參與比較:" + (Double.NaN != -1)); // true
System.out.println("NaN參與比較:" + (Double.NaN != Double.NaN)); // true
}

總結一下:正無窮大比任何數值都大;負無窮大比任何數值都??;NaN參與!=比較永遠是true(包括和自己比),除此之外都為false。

?? Float里的這三個常量和Double一樣嗎?

弱弱問一句:2023年了在實際業(yè)務開發(fā)中,不會真有人使用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規(guī)范了,不出意外每種編程語言的表現都是一致的。

Tips:JavaScript中的isFinite()方法是正向思維的,和Java里isInfinite()是“反”著來的哦

??遇到此異常怎么破?

解決問題的難度永遠在根因定位上,至于遇到此異常怎么破嘛,略?。?!

考慮到代碼的健壯性,實際場景中是可以對這些異常做預處理的:使用Double.isNaN()、Double.isInfinite()等方法來做分支邏輯

??總結

在Java中,浮點數0并非一個準確值,而是一個無限接近0的數。為此才鬧出這么多令人費解的“幺蛾子”,這是由計算機底層原理決定的,記住就好,無解。

計算機的運算基于數學,但貌似也有些“不同于”數學理論。這不,NaN這玩意就是這么神奇的存在。

責任編輯:武曉燕 來源: YourBatman
相關推薦

2014-05-16 13:44:27

2015-07-27 11:35:15

2015-02-01 15:52:27

2016-05-04 11:19:53

2013-10-15 15:54:46

Windows XPWindows 7

2021-02-09 08:31:38

線下環(huán)境 stable

2013-09-17 10:16:50

Infinite Mo傻瓜式

2018-08-22 06:33:30

2024-06-25 15:46:41

OpenAIChatGPTGPT-4

2020-12-15 10:14:47

NumPynanPython

2015-04-01 10:07:06

云計算概念公有云私有云

2022-08-10 14:52:02

DeepFakeAI

2018-03-15 10:36:30

2009-07-08 12:53:29

JDK源碼Java.lang.B

2022-07-18 13:35:24

數據安全網絡安全

2018-06-29 15:45:29

技術總監(jiān)管理者架構設計

2017-03-22 12:13:36

AI神經網絡模型算法

2017-05-23 15:23:08

金融云

2022-10-30 14:34:30

數據業(yè)務
點贊
收藏

51CTO技術棧公眾號