Exceptions and static initializers

A common problem in Java is Exceptions in static initializers. What on earth do you do with them? This has been discussed a bit on my local JUG recently, and here’s a bit of a summary.

Common solutions:

  • Wrap the Exception in an ExceptionInInitializerError and re-throw it
    • This causes the entire class to be marked as “errored”, as though it didn’t validate
    • Any further use of the class will result in a NoClassDefFoundException, which can be confusing
  • Log the Exception and continue as normal
    • If the log levels are set to high, nobody will ever see the Exception
    • Some Loggers get configured to drop stack traces
    • Sometimes the normal execution of code should stop
      • Someone configured something badly
      • The database is not running
  • Both of the above is a common pattern as well, and is generally considered “best practice”

One solution mentioned is to lazy-instantiate the static fields in the class. This is a nice idea, but has a few flaws:

  1. A synchronized block is needed, where static initializers are inherently very thread-safe
  2. It incurs an additional expense in methods that will be using these fields
  3. In the case of a singleton, it’s likely that the first method that will be called will cause the “lazy” code to run. Since classes are generally lazy-instantiated by the VM, a static initializer would achieve the same thing.

My solution was this one:

public class StaticInitializerExample {
 private static final Wrapper WRAPPER = createWrapper();

 private static abstract class Wrapper {
  private abstract StaticInitializerExample get();
 }

 private static Wrapper createWrapper() {
  try {
   final StaticInitializerExample c =
     new StaticInitializerExample();

   return new Wrapper() {
    public StaticInitializerExample get() {
     return c;
    }
   };
  } catch(final Exception e) {
    return new Wrapper() {
     public StaticInitializerExample get() {
      throw new RuntimeException(e);
     }
    };
  }
 }

 public static StaticInitializerExample getInstance() {
  return WRAPPER.get();
 }

 private StaticInitializerExample() throws Exception {
  // do code that could throw an exception
 }
}