記一次java中三元表達式的坑(避免踩坑)

近期一直在刷算法,原創文章寫的也比較少,今天的主題不算是一個很大的問題,是我做題的時候出來的,而且還曾在A廠的公眾號上看到過,今天自己整理一下,避免大家入坑。

這個問題是三元表達式會在計算的時候出現拆箱的運算,造成空指針異常。

一、問題重現

記一次java中三元表達式的坑(避免踩坑)

代碼很簡單,a是包裝類型Integer,初始值是null,b通過三元表達式進行賦值。運行一下這個代碼就會出現空指針異常:

記一次java中三元表達式的坑(避免踩坑)

為什麼會出現這個現象呢?下面我們來分析一下:

二、問題分析

剛剛這個空指針現象很容易我們就想到類型轉化上,三元表達式的類型轉換同樣要遵守一定的規則才可以。

1、三元操作符類型的轉換規則:

(1)若兩個操作數不可轉換,則不做轉換,返回值為Object類型

比如Object b = flag ? A : B,此時A和B是兩個不同的對象,不可轉換,那就把最終結果賦值給Object

(2)若兩個操作數是明確類型的表達式(比如變量),則按照正常的二進制數字來轉換,int類型轉換為long類型,long類型轉換為float類型等。

這個就比較容易理解了,比如float b = flag ? 1:1.0f。1為int類型向上轉即可。

(3)若兩個操作數中有一個是數字S,另外一個是表達式,且其類型標示為T,那麼,若數字S在T的範圍內,則轉換為T類型;若S超出了T類型的範圍,則T轉換為S類型。

這種情況就是剛剛我們所演示的例子,Integer b = flag ? 1 *2: a,結果是b=a,但是a是null,要強制轉換成Integer(1 * 2的類型),於是就出現了空指針。

(4)若兩個操作數都是直接量數字,則返回值類型為範圍較大者。

這種情況和第二種類似。

現在答案基本上出來了,出現空指針的原因是,a=null,要強制轉換Integer,於是出現了空指針,因為虛擬機看到一個null就找不到要轉化的對象了。

2、反編譯分析

現在我們找到Test的字節碼文件,輸入javap -c命令,反編譯一下:

記一次java中三元表達式的坑(避免踩坑)

答案現在應該清楚了,

3、為什麼要拆箱(重點)

為什麼要對a進行拆箱,直接把a=null賦值給b不就完事了嘛。這一點就需要我們注意一下那個前提條件,也就是說一個是數字,一個是表達式,剛剛的那個例子也驗證了這個觀點,現在我不是表達式,再來驗證一下:

記一次java中三元表達式的坑(避免踩坑)

現在我們可以看到不是表達式,依然會出現這個錯誤。彆著急,還有讓你更暈的,我們再來改變一下代碼:

記一次java中三元表達式的坑(避免踩坑)

這尼瑪噁心,我測試了很多不同的案例,基本上就分為這兩種情況。原因如下:

條件表達式?表達式 1 :表達式 2,假設結果是表達式2

(1)表達式1和2都為null,表達式2看到1是null,則不會進行拆箱。

(2)表達式1為數字或者是表達式,表達式2根據1的類型進行拆箱。

也就是說表達式2主要依據表達式1判斷是否進行拆箱操作。

三、問題解決

解決方案很簡單,那就是隻要遇見null在三元表達式裡,就儘量轉化為if結構。


分享到:


相關文章: