2012-10-06 66 views
11

由於在三元運算符中發生意外的類型轉換,導致前一天真的有點奇怪NullPointerException。鑑於這種(無用示例性)功能:通過Java三元運算符的自動裝箱行爲發生的NullPointerException

Integer getNumber() { 
    return null; 
} 

我期待以下兩個代碼段編譯後爲完全相同:

Integer number; 
if (condition) { 
    number = getNumber(); 
} else { 
    number = 0; 
} 

Integer number = (condition) ? getNumber() : 0; 

事實證明,如果conditiontrue,語句來工作正常的if,而在第二代碼段中的三元調度研究拋出一個NullPointerException。看起來好像三元操作決定在將結果自動裝箱回Integer之前,將兩個選項都輸入到int!!!實際上,如果我明確地將0轉換爲Integer,則例外情況會消失。換句話說:

Integer number = (condition) ? getNumber() : 0; 

是不一樣:

Integer number = (condition) ? getNumber() : (Integer) 0; 

因此,似乎三元運算符和等效的if-else -statement之間存在字節碼差異(我沒有想到)。這引出了三個問題:爲什麼會有差異?這是三元實現中的錯誤還是有類型轉換的原因?鑑於是有區別的,三元操作是否比等效的if -statement表現得更高或更低(我知道,差別不大,但仍然)?

+6

你認真地認爲三元運算符存在一個錯誤,而不是你對理解文檔的使用和運算符限制的理解*你認爲這種現實發生的可能性是什麼?考慮將你的問題的標題改爲「誤解三元運營商的工作方式」。 –

+1

這就是爲什麼我問這個問題,爲什麼編譯器決定getNumber()和0應該都計算爲一個int,如果我將結果賦給一個整數。對我而言,在比較之前將兩個參數強加於比較嚴格的兩種類型是完全沒有意義的,而不是比較之後實際需要的類型。爲什麼要拆箱,然後重新裝箱getNumber()? –

+0

您或我認爲應該發生的事情沒有區別。更重要的是JLS中明確記載的內容。 –

回答

13

根據JLS: -

類型的條件表達式的確定如下:

  • 如果第二和第三個操作數具有相同的類型(其可以是空型) ,那麼這就是條件 表達式的類型。
  • 如果第二個和第三個操作數中的一個是原始類型T,而另一個的類型是對T應用裝箱轉換
    (§5.1.7)的結果,則條件表達式的類型爲T
+1

所以,它應該是這樣的。留下兩者之間是否存在性能差異的問題,特別是在所有自動(非)裝箱發生的情況下。 –

+0

@Markus ..那麼,你不能說是否存在性能差異..這肯定會給程序員編碼的容易。但是,是的,因爲這包括'Unboxing'的一小部分......這不是以防萬一if-else ..所以可能性能會很低.. –

+0

@Markus ..但是考慮到三元運算符主要只用於'single'語句的情況。所以,這並不是一個擔心。當然,你將無法將整個表達式從if-else塊移到三元運算符。所以,它們都有優點和缺點。 –

11

的問題是:

Integer number = (condition) ? getNumber() : 0; 

強制getNumber的結果的取消裝箱和reboxing()。這是因爲三元(0)的錯誤部分是整數,所以它會嘗試將getNumber()的結果轉換爲int。而以下不:

Integer number = (condition) ? getNumber() : (Integer) 0; 

這不是一個錯誤,只是Java選擇做事情的方式。

+0

確切的,但是爲什麼? –

+2

@Markus請參閱[Java語言規範15.25](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25)'如果第二個和第三個之一操作數是原始類型T,而另一個的類型是對T應用裝箱轉換(§5.1.7)的結果,則條件表達式的類型是T.' – halex

2

這是應該如何工作的。三元運算符是而不是意思是等同於常規的if語句。的ifelse屍體是聲明,而部分以下?:表達,所需要的計算爲同一類型。

換句話說:a = b ? c : d不應該等於if (b) a = c; else a = d;。相反,b ? c : d本身就是一個表達式,將其結果賦值給a不會影響結果。