在這個浮躁的社會,咱們都學會了一種技能,快速學習使用各類開源庫、開源框架。html
學習使用各類高端大氣的技術,熱修復、插件化、模塊化、ORM……java
這些技能當然重要,可是有時候也要放慢腳步,耐着性子,打打基本功。android
不要看不起這些零零碎碎的基礎知識,這些基礎日積月累,慢慢的會讓你跟同事拉開差距。程序員
接下來,咱們直奔主題。開始咱們的基本功。web
System.out.println("1/0=" + 1/0);
複製代碼
大叔的靈魂拷問:oracle
上面的代碼會崩潰嗎?若是不會,會輸出什麼呢?app
上面的代碼會崩潰嗎?若是不會,會輸出什麼呢?框架
上面的代碼會崩潰嗎?若是不會,會輸出什麼呢?模塊化
運行直接崩潰。函數
咱們再來看一行代碼:
System.out.println("1.0/0=" + 1.0/0);
複製代碼
大叔的靈魂拷問:
會崩潰嗎?若是不會,會輸出什麼呢?
會崩潰嗎?若是不會,會輸出什麼呢?
會崩潰嗎?若是不會,會輸出什麼呢?
輸出日誌:
爲何浮點數除以0不會崩潰?
咱們先說結論:
由於java的float和double使用了IEEE 754標準。
這個標準規定:浮點數除以0等於正無窮或負無窮。
因而咱們打開Double這個類來看看。
infinity單詞的意思是:無窮大
NaN是Not a Number的簡稱,也就是非數。
因而,咱們發現,正無窮大的定義竟然是1.0f/0.0f 。負無窮大的定義爲**-1.0f/0.0f**,非數的定義爲0.0f/0.0f
我繼續看一個代碼段:
public static void main(String[] args) {
System.out.println("1.0/0=" + 1.0/0);
System.out.println("-1.0/0=" + -1.0/0);
double positiveInfinity = 1.0/0;
double negativeInfinity = -1.0/0;
System.out.println("(positiveInfinity==negativeInfinity)=" + (positiveInfinity==negativeInfinity));
System.out.println();
System.out.println("100.0/0=" + 100.0/0);
System.out.println("-100.0/0=" + -100.0/0);
System.out.println();
System.out.println("0.0/0=" + 0.0/0);
System.out.println("(-0.0==0.0)=" + (-0.0==0.0));
}
複製代碼
大叔的靈魂拷問:
上面的代碼段會輸出什麼呢?
上面的代碼段會輸出什麼呢?
上面的代碼段會輸出什麼呢?
運行結果:
注意關鍵詞1:
IEEE 754
java的單精浮點數float和雙精浮點數double,符合IEEE 754標準。
IEEE 754:二進制浮點數算術標準 ,這個標準描述了浮點數的存儲以及處理的一些規範。
注意關鍵詞2
A NaN value is used to represent the result of certain invalid operations such as dividing zero by zero.
翻譯過來的就是:NaN = 0.0/0.0
這也就是咱們看到Double類裏面NaN的定義。
咱們把這個文檔往下翻一些,會發現這麼一句:
for example,
1.0/0.0
has the value positive infinity, while the value of1.0/-0.0
is negative infinity.
翻譯成中文: 1.0/0.0 等於正無窮大,1.0/-0.0 等於負無窮大
因而咱們明白,浮點數除以0並不會崩潰,他是合法的,是符合IEEE 754規範。
也正是由於 IEEE 754的規範就是這麼規定的,因此java才這麼實現的。
下面這段來自,維基百科,en.wikipedia.org/wiki/Divisi…
咱們即便知道了,浮點數除以0不會崩潰,知道了IEEE標準,有什麼用呢?
不少人都會以爲,費這麼大勁,理解了,浮點數除以0不會崩潰,能有什麼用呢?平時咱們寫代碼都不會除以0。這麼騷的操做,我纔不會這麼幹。
是的,這個操做是有點騷,你不會這麼幹並不表明其餘同事不會這麼作。並且極可能你這麼幹了本身不知道。
在咱們寫業務代碼的時候,這個知識點,不多不多能用上。
可是當咱們恰好遇到除以0致使的bug的時候,這個時候就很是有用。
尤爲像android的app,用戶在線上遇到的bug,咱們沒法復現,只能經過日誌去分析排查時;
這個時候每一個程序員都是福爾摩斯,根據一行行日誌線索,配合實際代碼,排查問題的可能性。
若是咱們的認知是錯誤的,任何數除以0都會崩潰,那麼咱們的分析將會直接繞過真相去推理。因而得出結論,怎麼可能有bug,不可能的。
因而浪費了不少時間,去收集線索,去推翻咱們固有的認知,才能找到真相。
假如咱們一開始就有正確的常識,咱們就會少走不少彎路。
有位同事寫了這麼一段代碼
/** * 速度換算 米/秒 * @param distance 距離,單位米 * @param time 時間,單位秒 */
float computeSpeed(float distance, long time){
return distance/time;
}
複製代碼
而後有一天忽然某同事從另外一個進程獲取到數據傳入這個函數。
再而後,忽然有一天發現,速度顯示一串很奇怪的數字。
因而……接下來的故事,便如大家所想。
本來1小時就解決的bug,花了5個小時。
也正如,blog開頭的引言所表達的。不要小看這些零零碎碎的知識點。
參考資料: