標籤:android 異常 錯誤 java.lang.exceptioni
一.錯誤,原因
java.lang.ExceptionInInitializerError
二.原因
引起java.lang.ExceptionInInitializerError 錯誤的原因是:在類的初始化時,出錯。也就是說,在載入類時,執行static的屬性、方法塊時,出錯了。
比如
<span style="font-family:Times New Roman;">public class AA{ private static AA aa = new AA(); private AA(){//構造方法 init(); } public void init(){ .... }}</span>
初始化類時,會調用init方法,如果init方法出錯,這類初始化失敗,就會報java.lang.ExceptionInInitializerError錯誤。
同理,在執行
static{ ...}
方法塊時,也可能報這個錯。
三.原因分析
當在靜態初始化塊中出現了異常的時候,JVM會拋出 java.lang.ExceptionInInitializerError異常。
java中的靜態變數,是在類載入的時候進行初始化的。如果在這個靜態變數初始化的過程中出現了異常,就會拋出 java.lang.ExceptionInInitializerError異常。
任何異常都可能會引發這種情況,比如說,java.lang.ArrayIndexOutOfBound或者java.lang.NullPointerException。我們通常會被這個錯誤弄暈,覺得自己並沒有定義任何的靜態初始化塊,為什麼還會拋出ExceptionInInitializerError異常;事實上,Java預設會將靜態變數的初始化放在一個預設的靜態初始化塊中,然後按它們在源檔案中聲明的順序來進行初始化。比如說變數ABC聲明在第一行,在第二行中使用到了,而在第三行的時候才初始化,那麼第二行的代碼會拋出一個NullPointerException異常,這個異常會被封裝到一個ExceptionInInitializerError異常中,如果這段代碼在主線程中執行了,你會看到控制台或者記錄檔中出現這樣的錯誤資訊: "Exception in thread "main"java.lang.ExceptionInInitializerError"。
在一個擁有大量記錄檔的大型系統中,這樣的錯誤很容易被忽略,而程式員會得到一個java.lang.NoClassDefFoundError異常。不幸的是只有其他代碼使用到了這個類的時候才會出現這個錯誤,因為ExceptionInInitializerError導致了這個類無法載入。由於類載入失敗了,因此JVM會拋出NoClassDefFoundError。我們會去檢查類路徑,PATH,以及java.library.path看是不是缺少了這個類,卻又發現不了任何問題。如果在分析NoClassDefFoundError的原因,最好看下你的記錄檔中有沒有ExceptionInInitializerError,然後再考慮要不要檢查classpath。
Exception in thread"main" java.lang.ExceptionInInitializerError的原因 :
正如別的錯誤或者異常一樣,當看見這行資訊,你知道這是出現ExceptionInInitializerError異常了,這個異常是由於類載入過程中靜態塊初始化過程失敗所導致的。由於它出現在負責啟動程式的主線程中,因此你最好從主類中開始分析,這裡說的主類是指你在命令列參數中指定的那個,或者說是你聲明了public static void main(String args[])方法的那個類。如果你仔細地看一下完整的堆疊追蹤資訊,會發現引發ExceptionInInitializerError的類。ExceptionInInitializerError是LinkageError的子類,這意味著這個異常會導致你的類無法載入到JVM的記憶體中。現在我們來看一下這個樣本程式。
<span style="font-family:Times New Roman;">importjava.util.ArrayList;importjava.util.List; /** * Java Program to understand and solveExceptionInitializerError, which comes * When static initializer blocks throwsunchecked exception during class loading * and initialization. * * @author Javin Paul */ public classStaticInitializerDemo{ private static final List<CreditCard>cards = new ArrayList<CreditCard>(); private static CreditCard prefferdCard =cards.get(0); // 1st card is default public static boolean isVisa ="VISA".equalsIgnoreCase(prefferdCard.getNetwork()); public static void main(String args[]) { makePayment(prefferdCard); } public static void makePayment(CreditCard cc){ if (isVisa) { //offer 5% discount } // deduct payment } } class CreditCard{ private long card_number; //16 digit cardnumber private int cvv; // 3 digit cvv number private int expiryMonth; private int expiryYear; private String bank; private String network; public CreditCard(long card_number, int cvv,int expiryMonth, int expiryYear, String bank, String network) { super(); this.card_number = card_number; this.cvv = cvv; this.expiryMonth = expiryMonth; this.expiryYear = expiryYear; this.bank = bank; this.network = network; } /** * @return the card_number */ public final long getCard_number() { return card_number; } /** * @return the cvv */ public final int getCvv() { return cvv; } /** * @return the expiryMonth */ public final int getExpiryMonth() { return expiryMonth; } /** * @return the expiryYear */ public final int getExpiryYear() { return expiryYear; } /** * @return the bank */ public final String getBank() { return bank; } /** * @return the network */ public final String getNetwork() { return network; }} </span>
輸出:
<span style="font-family:Times New Roman;">Exception inthread "main" java.lang.ExceptionInInitializerErrorCaused by:java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(UnknownSource) at java.util.ArrayList.get(Unknown Source)atStaticInitializerDemo.<clinit>(StaticInitializerDemo.java:15)</span>
看一下棧跟蹤資訊,知道真正的異常是java.lang.IndexOutOfBoundsException,它在StaticInitiazerDemo的第二行被拋出來了。這是由於調用了ArrayList的get()方法並傳入了位置0,而這個ArrayList的大小也是0(Index: 0, Size: 0)。看到這條資訊後你知道當我們想從列表中取出第一張CreditCard時,這個列表是空的。
四.解決辦法
解決注意事項:
如何解決Exception inthread "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塊來進行處理。
需要謹記的是這個異常的一個副作用是NoClassDefFoundError,而Java程式拋出這個異常的位置可能會離java.lang.ExceptionInInitializerError很遠,這取決於用戶端代碼何時引用到這個類。因此,在查看類路徑解決NoClassDefFoundError異常之前,最好先看看日誌有沒有出現ExceptionInInitializerError。
五.參考網址
1. http://www.2cto.com/kf/201309/241190.html
2. http://www.tuicool.com/articles/IVBVn2
java.lang.ExceptionInInitializerError