1、三目運算符java
對於條件表達式b?x:y,先計算條件b,而後進行判斷。若是b的值爲true,計算x的值,運算結果爲x的值;不然,計算y的值,運算結果爲y的值。一個條件表達式從不會既計算x,又計算y。條件運算符是右結合的,也就是說,從右向左分組計算。例如,a?b:c?d:e將按a?b:(c?d:e)執行。程序員
2、自動裝箱與自動拆箱express
基本數據類型的自動裝箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0開始提供的功能。 通常咱們要建立一個類的對象實例的時候,咱們會這樣: Class a = new Class(parameters); 當咱們建立一個Integer對象時,卻能夠這樣: Integer i = 100;(注意:和 int i = 100;是有區別的 ) 實際上,執行上面那句代碼的時候,系統爲咱們執行了: Integer i = Integer.valueOf(100); 這裏暫且不討論這個原理是怎麼實現的(什麼時候拆箱、什麼時候裝箱),也略過普通數據類型和對象類型的區別。咱們能夠理解爲,當咱們本身寫的代碼符合裝(拆)箱規範的時候,編譯器就會自動幫咱們拆(裝)箱。那麼,這種不被程序員控制的自動拆(裝)箱會不會存在什麼問題呢?app
3、問題回顧指針
首先,經過你已有的經驗看一下下面這段代碼。若是你獲得的結果和後文分析的結果一致(而且你知道原理),那麼請忽略本文。若是不一致,請跟我探索下去。code
Map<String,Boolean> map = new HashMap<String, Boolean>(); Boolean b = (map!=null ? map.get("test") : false);
以上這段代碼,是咱們在不注意的狀況下有可能常常會寫的一類代碼(在不少時候咱們都愛使用三目運算符)。固然,這段代碼是存在問題的,執行該代碼,會報NPE.對象
Exception in thread "main" java.lang.NullPointerException
首先能夠明確的是,既然報了空指針,那麼必定是有些地方調用了一個null的對象的某些方法。在這短短的兩行代碼中,看上去只有一處方法調用map.get("test"),可是咱們也都是知道,map已經事先初始化過了,不會是Null,那麼究竟是哪裏有空指針呢。咱們接下來反編譯一下該代碼。看看咱們寫的代碼在通過編譯器處理以後變成了什麼樣。get
反編譯後代碼以下:編譯器
HashMap hashmap = new HashMap(); Boolean boolean1 = Boolean.valueOf(hashmap == null ? false : ((Boolean)hashmap.get("test")).booleanValue());
看完這段反編譯以後的代碼以後,通過分析咱們大概能夠知道問題出在哪裏。((Boolean)hashmap.get("test")).booleanValue()的執行過程及結果以下:hash
hashmap.get(「test」)->null;
(Boolean)null->null;
null.booleanValue()->報錯
好,問題終於定位到了。那麼接下來看看如何解決該問題以及爲何會出現這種問題。
4、原理分析
經過查看反編譯以後的代碼,咱們準確的定位到了問題,分析以後咱們能夠得出這樣的結論:NPE的緣由應該是三目運算符和自動拆箱致使了空指針異常。
那麼,這段代碼爲何會自動拆箱呢?這實際上是三目運算符的語法規範。參見jls-15.25,摘要以下:
If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.
If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.
If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.
簡單的來講就是:當第二,第三位操做數分別爲基本類型和對象時,其中的對象就會拆箱爲基本類型進行操做。
因此,結果就是:因爲使用了三目運算符,而且第2、第三位操做數分別是基本類型和對象。因此對對象進行拆箱操做,因爲該對象爲null,因此在拆箱過程當中調用null.booleanValue()的時候就報了NPE。
5、問題解決
若是代碼這麼寫,就不會報錯:
Map<String,Boolean> map = new HashMap<String, Boolean>(); Boolean b = (map!=null ? map.get("test") : Boolean.FALSE);
就是保證了三目運算符的第二第三位操做數都爲對象類型。
這和三目運算符有關。