1. 程式人生 > >JAVA陷阱---三元表示式潛藏的坑

JAVA陷阱---三元表示式潛藏的坑

當熟悉的三元表示式遇到裝/拆箱發生了未預料到的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"