1. Overview
In this quick tutorial, we're going to see what causes Java to throw an instance of the ExceptionInInitializerError exception.
We'll start with a little bit of theory. Then we'll see a few examples of this exception in practice.
2. The ExceptionInInitializerError
The ExceptionInInitializerError indicates that an unexpected exception has occurred in a static initializer. Basically, when we see this exception, we should know that Java failed to evaluate a static initializer block or to instantiate a static variable.
In fact, every time any exception happens inside a static initializer, Java automatically wraps that exception inside an instance of the ExceptionInInitializerError class. This way, it also maintains a reference to the actual exception as the root cause.
Now that we know the rationale behind this exception, let's see it in practice.
3. Static Initializer Block
To have a failed static block initializer, we're going to divide an integer by zero intentionally:
public class StaticBlock { private static int state; static { state = 42 / 0; } }
Now if we trigger the class initialization with something like:
new StaticBlock();
Then, we would see the following exception:
java.lang.ExceptionInInitializerError at com.baeldung...(ExceptionInInitializerErrorUnitTest.java:18) Caused by: java.lang.ArithmeticException: / by zero at com.baeldung.StaticBlock.<clinit>(ExceptionInInitializerErrorUnitTest.java:35) ... 23 more
As mentioned earlier, Java throws the ExceptionInInitializerError exception while maintaining a reference to the root cause:
assertThatThrownBy(StaticBlock::new) .isInstanceOf(ExceptionInInitializerError.class) .hasCauseInstanceOf(ArithmeticException.class);
It's also worth mentioning that the <clinit> method is a class initialization method in the JVM.
4. Static Variable Initialization
The same thing happens if Java fails to initialize a static variable:
public class StaticVar { private static int state = initializeState(); private static int initializeState() { throw new RuntimeException(); } }
Again, if we trigger the class initialization process:
new StaticVar();
Then the same exception occurs:
java.lang.ExceptionInInitializerError at com.baeldung...(ExceptionInInitializerErrorUnitTest.java:11) Caused by: java.lang.RuntimeException at com.baeldung.StaticVar.initializeState(ExceptionInInitializerErrorUnitTest.java:26) at com.baeldung.StaticVar.<clinit>(ExceptionInInitializerErrorUnitTest.java:23) ... 23 more
Similar to static initializer blocks, the root cause of the exception is also preserved:
assertThatThrownBy(StaticVar::new) .isInstanceOf(ExceptionInInitializerError.class) .hasCauseInstanceOf(RuntimeException.class);
5. Checked Exceptions
As part of the Java language specification (JLS-11.2.3), we can't throw checked exceptions inside a static initializer block or static variable initializer. For instance, if we try to do so:
public class NoChecked { static { throw new Exception(); } }
The compiler would fail with the following compilation error:
java: initializer must be able to complete normally
As a convention, we should wrap the possible checked exceptions inside an instance of ExceptionInInitializerError when our static initialization logic throws a checked exception:
public class CheckedConvention { private static Constructor<?> constructor; static { try { constructor = CheckedConvention.class.getDeclaredConstructor(); } catch (NoSuchMethodException e) { throw new ExceptionInInitializerError(e); } } }
As shown above, the getDeclaredConstructor() method throws a checked exception. Therefore, we caught the checked exception and wrapped it as the convention suggests.
Since we're already returning an instance of ExceptionInInitializerError exception explicitly, Java won't wrap this exception inside yet another ExceptionInInitializerError instance.
However, if we throw any other unchecked exception, Java will throw another ExceptionInInitializerError:
static { try { constructor = CheckedConvention.class.getConstructor(); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } }
Here, we're wrapping the checked exception inside an unchecked one. Because this unchecked exception is not an instance of ExceptionInInitializerError, Java will wrap it again, resulting in this unexpected stack trace:
java.lang.ExceptionInInitializerError at com.baeldung.exceptionininitializererror... Caused by: java.lang.RuntimeException: java.lang.NoSuchMethodException: ... Caused by: java.lang.NoSuchMethodException: com.baeldung.CheckedConvention.<init>() at java.base/java.lang.Class.getConstructor0(Class.java:3427) at java.base/java.lang.Class.getConstructor(Class.java:2165)
As shown above, if we follow the convention, then the stack trace would be much cleaner than this.
5.1. OpenJDK
Recently, this convention is even used in the OpenJDK source code itself. For instance, here's how the AtomicReference is using this approach:
public class AtomicReference<V> implements java.io.Serializable { private static final VarHandle VALUE; static { try { MethodHandles.Lookup l = MethodHandles.lookup(); VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); } } private volatile V value; // omitted }
6. Conclusion
In this tutorial, we saw what causes Java to throw an instance of the ExceptionInInitializerError exception.
As usual, all the examples are available over on GitHub.