JAVA陷阱---三元表示式潛藏的坑
阿新 • • 發佈:2019-05-18
當熟悉的三元表示式遇到裝/拆箱發生了未預料到的NPE 以下程式碼都是在 jdk 1.8.0_172 版本下執行
java程式碼如下,註釋位置會丟擲NPE:
public class TestThree { public static void main(String[] args) { Double a = 1D; Double b = 2D; Double c = null; Double d = false ? a*b : c; // 這裡會丟擲NPE System.out.println("finished"); } }
猜測由於a*b,Double都進行了拆箱,c因為是null,進行拆箱時就丟擲了NPE,為了驗證,我們使用javap -c命令看下簡單的位元組碼資訊
如上圖所示,第12--21行即c的操作過程,可以看出第18行Double.doubleValue獲取c的小double值就是丟擲NPE的罪魁禍首。
但是有個疑問,很明顯可以看出,經過javac的優化,ab根本不會執行,a、b也都沒有拆箱的操作,為什麼要對c進行拆箱呢,直接將null賦值給d不是更簡捷,僅僅因為程式碼中使用了ab進行乘法運算就導致了c的拆箱嗎? 我們來做個驗證:
public class TestThree { public static void main(String[] args) { //Double a = 1D; //Double b = 2D; Double c = null; Double d = false ? null : c; // 這裡不會丟擲NPE System.out.println("finished"); } }
上面的程式碼能夠成功執行,我們來看下反編譯出的位元組碼內容
可以看到確實沒有對c的Double.valueOf方法的呼叫,之前對c的拆箱確實是由於a*b運算導致的。
至此,我們可以得出一個猜想,在三元表示式中,如果一個結果執行了數學運算,即使表示式的判斷條件短路了此運算,另外一個結果也會由於拆箱而可能導致NPE的發生。
最後留一個問題,下面的程式碼是否會丟擲NPE,其反編譯後的程式碼又會是什麼樣子的,想象一下~
public class TestThree {
public static void main(String[] args) {
Double a = 1D;
Double b = 2D;
Double c = null;
Double d = false ? 1 : c; // 這裡會不會丟擲NPE???
System.out.println("finished"