1. 程式人生 > >Java中的java.lang.ExceptionInInitializerError異常及其解決方法——JM

Java中的java.lang.ExceptionInInitializerError異常及其解決方法——JM

當在靜態初始化塊中出現了異常的時候,JVM會丟擲 java.lang.ExceptionInInitializerError異常。如果你瞭解Java中的靜態變數,你會知道它們是在類載入的時候進行初始化的。如果在這個靜態變數初始化的過程中出現了異常,那麼就會丟擲 java.lang.ExceptionInInitializerError異常。任何異常都可能會引發這種情況,比如說,java.lang.ArrayIndexOutOfBound或者java.lang.NullPointerException。Java開發人員通常會被這個錯誤弄暈,他覺得自己並沒有定義任何的靜態初始化塊,為什麼還會丟擲ExceptionInInitializerError異常;事實上,Java預設會將靜態變數的初始化放在一個預設的靜態初始化塊中,然後按它們在原始檔中宣告的順序來進行初始化。比如說變數ABC宣告在第一行,在第二行中使用到了,而在第三行的時候才初始化,那麼第二行的程式碼會丟擲一個NullPointerException異常,這個異常會被封裝到一個ExceptionInInitializerError異常中,如果這段程式碼在主執行緒中執行了,你會看到控制檯或者日誌檔案中出現這樣的錯誤資訊: "Exception in thread "main" java.lang.ExceptionInInitializerError"。在一個擁有大量日誌檔案的大型系統中,這樣的錯誤很容易被忽略,而程式設計師會得到一個java.lang.NoClassDefFoundError異常。不幸的是只有當別人使用到了這個類的時候才會出現這個錯誤,因為ExceptionInInitializerError導致了這個類無法載入。由於類載入失敗了,因此JVM會丟擲NoClassDefFoundError。有的時候這會誤導Java開發人員,他們會檢查類路徑,PATH,以及java.library.path看是不是缺少了這個類,卻又發現不了任何問題,這讓他們很困惑。如果你在分析NoClassDefFoundError的原因,你最好看下你的日誌檔案中有沒有ExceptionInInitializerError,然後再考慮要不要檢查classpath。在稍後的部分,我們將會看到如何去解決這個問題。 

Exception in thread "main" java.lang.ExceptionInInitializerError的原因
正如別的錯誤或者異常一樣,當你看見這行資訊,你知道這是出現ExceptionInInitializerError異常了,這個異常是由於類載入過程中靜態塊初始化過程失敗所導致的。由於它出現在負責啟動程式的主執行緒中,因此你最好從主類中開始分析,這裡說的主類是指你在命令列引數中指定的那個,或者說是你聲明瞭public static void main(String args[])方法的那個類。如果你仔細地看一下完整的堆疊跟蹤資訊,你其實什麼也不用做,因為JVM已經把類名給打印出來了,這就是引發ExceptionInInitializerError的類。ExceptionInInitializerError是LinkageError的子類,這意味著這個異常會導致你的類無法載入到JVM的記憶體中。可以看到ExceptionInInitializerError是繼承自LinkageError的。還應當知道的是,像RuntimeException一樣,Error也是未檢查異常,編譯器是不去檢查有沒有相應的異常處理程式碼的。

如何解決Exception in thread "main" java.lang.ExceptionInInitializerError
需要記住以下幾點: 
1. "Exception in thread "main" java.lang.ExceptionInInitializerError"意味著異常出現在主執行緒,並且是LinkageError的一個子類java.lang.ExceptionInInitializerError,這是JVM類載入失敗時才丟擲的,原因是靜態初始化程式碼中出現了諸如IndexOutOfBoundsException或者NullPointerException這樣的RuntimeException。


2. 記住JVM會將所有的靜態變數的初始化按它們在原始檔中的出現順序放到一個靜態初始化塊中。因此,不要覺得沒有看到靜態初始塊就認為不會出現這個異常。事實上,你得確保靜態變數的正確順序,比如說,如果 一個變數初始化的時候用到了另一個變數,你得確保這個變數在前面已經初始化過了。 
3. 如果別的程式碼想要使用這個類,則會丟擲ExceptionInInitializerError異常,而它又會導致ClassNotFoundException或者NoClassDefFoundError。為什麼?因為這個類載入失敗了,並沒有載入到JVM的記憶體中。因此如果你在解決類不存在之類的異常時,先看看你的日誌檔案中有沒有這個異常。 
4. 記住靜態初始化程式碼塊會丟擲RuntimeException而不是已檢查異常,而後者需要有對應的catch塊來進行處理。 
這就是關於Exception in thread "main" java.lang.ExceptionInInitializerError的所有東西了。你已經瞭解到瞭如何去跟蹤此類問題,並找出丟擲這個異常的罪魁禍首。需要謹記的是這個異常的一個副作用是NoClassDefFoundError,而Java程式丟擲這個異常的位置可能會離java.lang.ExceptionInInitializerError很遠,這取決於你的客戶端程式碼何時引用到這個類。因此,在檢視類路徑解決NoClassDefFoundError異常之前,最好先看看日誌有沒有出現ExceptionInInitializerError。