当在静态初始化块中出现了异常的时候,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"。在稍后的部分,咱们将会看到如何去解决这个问题。
Exception in thread "main" java.lang.ExceptionInInitializerError的缘由
正如别的错误或者异常同样,当你看见这行信息,你知道这是出现ExceptionInInitializerError异常了,这个异常是因为类加载过程当中静态块初始化过程失败所致使的。因为它出如今负责启动程序的主线程中,所以你最好从主类中开始分析,这里说的主类是指你在命令行参数中指定的那个,或者说是你声明了public static void main(String args[])方法的那个类。若是你仔细地看一下完整的堆栈跟踪信息,你其实什么也不用作,由于JVM已经把类名给打印出来了,这就是引起ExceptionInInitializerError的类。ExceptionInInitializerError是LinkageError的子类,这意味着这个异常会致使你的类没法加载到JVM的内存中。如今咱们来看一下这个示例程序,它在执行的时候会抛出下面的异常:
java
Exception in thread "main" java.lang.ExceptionInInitializerError 程序员
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 ui
at java.util.ArrayList.rangeCheck(ArrayList.java:635) this
at java.util.ArrayList.get(ArrayList.java:411) spa
at StaticInitiazerDemo.<clinit>(StaticInitiazerDemo.java:15) .net
Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:635) at java.util.ArrayList.get(ArrayList.java:411) at StaticInitiazerDemo.<clinit>(StaticInitiazerDemo.java:15)
看一下栈跟踪信息,你知道真正的异常是java.lang.IndexOutOfBoundsException,它在StaticInitiazerDemo的第二行被抛出来了。这是因为你调用了ArrayList的get()方法并传入了位置0,而这个ArrayList的大小也是0(Index: 0, Size: 0)。看到这条信息后你知道当咱们想从列表中取出第一张CreditCard时,这个列表是空的。
命令行
import java.util.ArrayList; 日志
import java.util.List;
/**
* Java Program to understand and solve ExceptionInitializerError, which comes
* When static initializer blocks throws unchecked exception during class loading
* and initialization.
*
* @author Javin Paul
*/
public class StaticInitializerDemo{
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 card number
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;
}
}
import java.util.ArrayList; import java.util.List; /** * Java Program to understand and solve ExceptionInitializerError, which comes * When static initializer blocks throws unchecked exception during class loading * and initialization. * * @author Javin Paul */ public class StaticInitializerDemo{ 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 card number 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; } }
输出:
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at StaticInitializerDemo.<clinit>(StaticInitializerDemo.java:15)
Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(Unknown Source) at java.util.ArrayList.get(Unknown Source) at StaticInitializerDemo.<clinit>(StaticInitializerDemo.java:15)
这里是Java中全部Error类的类结构。你能够看到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。