Saturday, 7 June 2014

Exception in thread "main" java.lang.ExceptionInInitializerError in Java Program

JVM throws java.lang.ExceptionInInitializerError, when there is an Exception inside static initializer block. If you know about static variable in Java, then you may know that they are initialized at the time of class loading. If there is an Exception during that initialization of static variables, you will see ExceptionInInitializerError in Java. This could be any exception e.g. java.lang.ArrayIndexOutOfBound or java.lang.NullPointerException. Java developers often confused with this error because, they think that they have not defined any static initializer block, then how come they are getting ExceptionInInitializerError; well, by default Java combines all static variable initialization inside a static initializer block and initialize them in the order they are declared in source file. If suppose a variable ABC is declared at line 1, used at line 2 but initialized at line 3, then code at line 2 will throw java.lang.NullPointerException, which will be wrapped by JVM in ExceptionInInitializerError, and if that code happens to be executed by main thread then you will see "Exception in thread "main" java.lang.ExceptionInInitializerError" in your console or log file. In a large application with huge log files sometime this error got unnoticed, and programmers get alerted by dreaded java.lang.NoClassDefFoundError. Unfortunately this error comes when client class tries to use the class, which was not loaded because of ExceptionInInitializerError . Since class loading was failed earlier, JVM is now throwing NoClassDefFoundError. Sometime this misleads Java developer, and they start looking at classpath, path and java.library.path for missing class, and confused them with hell not finding any anomalies.  If you are investigating cause of NoClassDefFoundError, it's always a better idea to check your application log files for ExceptionInInitializerError before looking at CLASSPATH. In this article, we will see an example code, which generates exception during static initialization and results in "Exception in thread "main" java.lang.ExceptionInInitializerError". In later part, we will see how to fix this error.




Cause of "Exception in thread "main" java.lang.ExceptionInInitializerError"

As with any other error or exception, by first looking at this line, you know that exception is java.lang.ExceptionInInitializerError, which comes because of failure during class loading and static initialization. Since it has occurred inside Main thread, which is responsible for starting application, it’s better to start your investigation from Main class, the class which you provided to java command at command line or same class where you have written your public static void main(String args[]) method. Now if you look at full stacktrace carefully, you don't need to do anything because JVM prints name of the class, which caused ExceptionInInitializerError. It's also a subclass of LinkageError, which means if this error has occurred then you class will not be loaded into JVM memory. Now let's take a look at our example program, which upon execution, throwing following error :

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)

By looking at this stack trace, we know that actual error is java.lang.IndexOutOfBoundsException, which came at line 12 of StaticInitiazerDemo class. It came because of call to get() method of ArrayList with index 0 and come because size of ArrayList was also zero (Index: 0, Size: 0 part of stack-trace). Now by following this information, you know that our List<CreditCard> is empty, when we try to get first CreditCard from this list.

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;
    }
}

Output
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)

Here is class hierarchy of all Error class in Java. You can see that ExceptionInInitializerError inherit from LinkageError. Its also worth knowing that like RuntimeException, Errors are also unchecked and compiler doesn't check for mandatory error handling code.
Exception in thread "main" java.lang.ExceptionInInitializerError fix

Things to remember:

1) Remember "Exception in thread "main" java.lang.ExceptionInInitializerError" means Exception has occurred in main thread, and it is java.lang.ExceptionInInitializerError, which is sub-class of LinkageError and comes when JVM tries to load a class and it failed because of any RuntimeException in static initializer block e.g. IndexOutOfBoundsException or NullPointerException.

2) Remember that JVM combines all static variable initialization into one static initializer block in the order they appear in source file. So, don't think that absence of explicit static initializer block will not cause this error. In fact, you must ensure correct order of static variables i.e. if one variable initialization uses another variable then make sure that is initialized first.

3) Down the line, java.lang.ExceptionInInitializerError can cause ClassNotFoundException or NoClassDefFoundError, if some other code tries to use the class, which caused ExceptionInInitializerError. Why? because loading of that class is failed and it’s not available inside JVM memory. So always check your log files for this before even if you are looking to solve any problem related to class not found.

4) Remember Static initializer block can throw RuntimeException but not checked Exception, because later required mandatory catch block for handling.

That's all about "Exception in thread "main" java.lang.ExceptionInInitializerError". We have learned how to troubleshoot this error and find the real culprit, which throwing this error. Always, remember potential side effect of this error is NoClassDefFoundError, which your Java application may throw far from this error, depending upon when other client code refer to this class in question. So, it’s always better to look for ExceptionInInitializerError, before playing with ClassPath to troubleshoot NoClassDefFoundError in Java.

No comments:

Post a Comment