Saturday, September 30, 2023

How to Fix Exception in thread "main" java.lang.ExceptionInInitializerError in Java Program? Example

JVM throws java.lang.ExceptionInInitializerError, when there is an Exception inside static initializer block. If you know about static variables 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 are 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 the source file.

I 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 the 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 sometimes this error got unnoticed, and programmers get alerted by the dreaded java.lang.NoClassDefFoundError

Unfortunately, this error comes when the 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.

Sometimes this misleads Java developers, 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 the 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 exceptions during static initialization and results in "Exception in thread "main" java.lang.ExceptionInInitializerError". In the 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 the main thread, which is responsible for starting the application, it’s better to start your investigation from the Main class, the class which you provided to java command at the command line or the same class where you have written your public static void main(String args[]) method. 

Now if you look at full stack trace 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 your class will not be loaded into JVM memory. 

Now let's take a look at our example program, which upon execution, throwing the 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 the 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 the 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 the 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 a class hierarchy of all Error class in Java. You can see that ExceptionInInitializerError inherit from LinkageError. It's 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 the main thread, and it is java.lang.ExceptionInInitializerError, which is a subclass 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 the source file. So, don't think that absence of an explicit static initializer block will not cause this error. In fact, you must ensure the 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 codes refers to this class in question. 

So, it’s always better to look for ExceptionInInitializerError, before playing with ClassPath to troubleshoot NoClassDefFoundError in Java.

Let me know if you are facing this issue and need help. Please post the full error and context like what you are trying to do and when you get this error, it will help me to understand and solve your problem faster without back and forth questioning. 


No comments :

Post a Comment