Friday, April 1, 2011

Throws RunTimeException in Java Class Static Initializer?

When you want to run some logic during class initialization, you put it into so called class initializer e.g. something like this:

public class MyTest {   
    static {
        if (some-condition)
           throw new RuntimeException("something wrong");
    public void test() {
        System.out.println("throw RTE in static initializer");

However there is some caveat. If the RuntimeException is thrown, class MyTest will still be loaded, but in erroneous state. So you can't do handle the following scenario.
Assume in the static initalizer, you want to retrieve some external property values and the RTE will be thrown if some property value is not configured yet. MyTest is also supposed to be deployed on the server side.
When JVM first attempted to load MyTest, the RTE was thrown because of some missing property value. The user saw the RTE and configured the missing property values. Now he/she hopes to be able to access this class.
However when MyTest is being accessed again, he/she will get NoClassDefFoundError.

This error is so confusing in this case because binary code of MyTest was indeed found by the JVM classloader. However it is just in erroneous state.
In order to find details, you need to read section 2.17 Execution in JVM Specification. Basically a class like MyTest must go throw 3 stages in order before it is being put in use: Loading, Linking and Initialization.  The static initializer is executed in Initialization. If any exception is thrown in class initialization, JVM will throw ExceptionInInitializerError and put the class in erroneous state. (since the Initialization is after loading, the class was indeed found by JVM and loaded)
Based on Step 5 in section 2.17.5 in the above reference, JVM will stop initializing by throwing NoClassDefFoundError even the class has been found and loaded.

Because of this caveat, you have to throw an exception in a class constructor and use a class variable as a flag to void repeating execution of your logic that is supposed to be run only once.

No comments:

Post a Comment