2009-07-22 33 views
27

我一直想知道爲什麼JVM不會告訴你哪個指針(或者更確切地說哪個變量)在拋出NullPointerException時爲空。爲什麼Java不告訴你哪個指針是空的?

行號不夠具體,因爲違規行通常可能包含許多可能導致錯誤的變量。

是否有任何編譯器或JVM標誌使這些異常消息更有用?

+9

作爲一名專業的Java開發人員,這對於我來說從未成爲一個問題。如果在一行中有很多引用可能爲空,那麼可能是時候將其分解爲多行。 – MattC 2009-07-22 22:06:23

+6

@mattc,你從來沒有與其他人的圖書館代碼工作? – 2009-07-22 22:51:41

+0

@MATC:當你需要在長if-else-if塊的中間條件下調用具有多個參數的函數時,經常會出現這種情況。將它分成多行意味着將會在if語句的頂部之前聲明一堆虛擬變量。我會說在大多數情況下,這在代碼可讀性和風格方面會更成問題。 – kpozin 2009-07-23 14:28:05

回答

49

這是因爲當沒有可用的名稱時總是會發生取消引用。該值被加載到操作數堆棧中,然後傳遞給其中一個解引用它的JRE操作碼。但是,操作數堆棧沒有與空值關聯的名稱。它只有'空'。通過一些聰明的運行時跟蹤代碼,可以派生出一個名稱,但這會增加開銷和限制值。

因此,沒有JRE選項會打開空指針異常的額外信息。

在此示例中,引用存儲在本地插槽1中,該插槽映射到本地變量名稱。但解除引用發生在invokevirtual指令,該指令只看到堆棧上的「空」值,然後將引發異常:

15 aload_1 
16 invokevirtual #5 

同樣有效。將數組負載後跟一個間接引用,但是在這種情況沒有名稱可以映射到'空'值,只是一個索引而不是另一個值。

76 aload 5 
78 iconst_0 
79 aaload 
80 invokevirtual #5 

不能靜態分配的名稱給每個指令會 - 這個例子中會產生大量的字節碼的,但你可以看到,取消引用指令將接受或objA或objB,你需要跟蹤此動態報告是正確的,因爲這兩個變量流向相同的取消引用指令:

(myflag ? objA : objB).toString() 
12

一旦你JIT的代碼,它只是本地指針數學,並且如果本地代碼中的任何指針爲null它會引發異常。如果將該組件還原爲原始變量,並且考慮到JIT將生成的代碼優化爲不同的級別,這往往不可能發生破壞性的性能影響。

0

如果您將行分成多行而不是在一行上進行多個方法調用,或者如果您在該行上設置斷點並通過調試器遍歷行,則可以很容易地確定哪些引用非常容易。

0

如果

行號是不夠具體 ,因爲出錯的行往往能 包含可能 造成的錯誤很多的變化。

話,我建議:

  1. 該行分解成多個行和分配可能NullPointerException - 產生值的臨時變量。
  2. 使用調試器並逐步調用每個方法調用,直到找到導致問題的調用者。
0

不幸的是,這只是Java的工作方式。

如果這是「你的」代碼,然後簡單地分配富之後添加片段喜歡

if (foo == null) { 
    throw new NullPointerException("foo == null"); 
} 

。如果foo是一個參數,那麼在方法體的開始處立即檢查,然後拋出IllegalArgumentException。

這應該可以幫助你澄清問題。

0

您可以在空指針異常在Eclipse中調試獲得異常的具體原因時,添加一個斷點。

相關問題