某日,同事給我展示了一塊代碼,問我有沒有什麼問題。(代碼如下 代碼塊1):
int i = 1;
Boolean a = null;
boolean b = false;
System.out.println(i == 1 ? a : b);
集智慧與美貌於一身的我一眼就發現了其中的端倪:當然會報 NPE 了!
但是如果代碼變成這樣的呢(如下 代碼塊2)?
int i = 1;
boolean a = true;
Boolean b = null;
System.out.println(i == 1 ? a : b);
上述代碼塊就是正常的。
爲什麼呢?
這就涉及到了Java中 三目運算符 和 自動裝箱/拆箱 的問題了。
代碼塊1會報錯是因爲條件滿足,取 a 的值。在取 a 的值時,三目運算符中既有基本類型,又有引用類型;JVM會幫我們把引用類型的數據轉換爲基本類型。通過查看 class 文件看到如下代碼(代碼塊3):
int i = 1;
Boolean a = null;
boolean b = false;
System.out.println(i == 1 ? a.booleanValue() : b);
因爲 a 是引用類型,此時調用 a 的方法就會報NPE了。
代碼塊2爲什麼不會報錯呢?
此時三目運算符中的條件滿足,直接就取 a 的值了,因爲 a 是基本類型的,直接就拿來用了,所以程序正常。可以看到 class 文件如下(代碼塊4):
int i = 1;
boolean a = true;
Boolean b = null;
System.out.println(i == 1 ? a : b.booleanValue());
但在實際的業務場景中,我們的代碼不會上上述一樣是 i == 1 的寫法,大部分情況下是動態判斷的。如何避免踩進上述的坑中呢?
其實要解決這個問題也很簡單,就是不讓JVM幫我們拆箱。即把 a 和 b 兩個對象都改爲 Boolean 或 boolean,只要兩個對象統一就好了。
避免採坑的代碼:
int i = 1;
Boolean a = Boolean.TRUE;
Boolean b = Boolean.FALSE;
System.out.println(i == 1 ? a : b);
或
int i = 1;
boolean a = true;
boolean b = false;
System.out.println(i == 1 ? a : b);
總結:
不止 Boolean/boolean 有這個問題,像 Byte / byte、Integer / int、Short / short、Long / long、Character / char、Float / float、Double / double 都會有這樣的問題。只要代碼規範一點,就不會坑到隊友啦 ╮( ̄▽ ̄)╭
最後祝大家碼出好心情,碼出幸福人生!