It's really hard to catch those. As a consequence, it is highly advisable to ensure that static initializers do not throw anything that one could feasibly want to catch. (e.g. throwing an OutOfMemoryError is fine, it's not likely someone would want to write code that catches this and does an alternative path or attempts to solve the problem).
This generally starts by replacing your static initializer with a method invocation. Replace:
static int a; static {a = 1/0; }
with:
static int a = calculateA();
private static int calculateA() {
return 1/0;
}
This is just a step along the path, of course. Move the initializing code (the calculateA method) to a separate class and now you can test it on its own, without even running into problem of catching exceptions thrown during static init of a class.
Once you've taken care of this, you can use this 'trick' to move the problem around. Imagine that the value of a is required for 2 of the methods in this class. Then, 'defer' the exception:
public class Example {
private static final int a;
private static final Throwable aProblem;
static {
int a = 0;
Throwable aProblem = null;
try {
a = calculateA();
} catch (RuntimeException e) {
aProblem = e;
}
Example.a = a;
Example.aProblem = aProblem;
}
private static int calculateA() { return 1/0; }
public static void apiMethodUsingA1() {
if (aProblem != null) throw aProblem;
return a;
}
public static void apiMethodUsingA2() {
if (aProblem != null) throw aProblem;
return a + 5;
}
}
If none of these options are available, for example because A is not written by you and cannot be changed, then you must delegate the A class as 'bad API / crappy library', and you do what you always do when you face such a library: Work around it, accept that you need to write hard to maintain / ugly code, and if it's really bad, write a wrapper to isolate the problems. Maybe even use reflection.
This is one guaranteed way to isolate the exception into a codeblock:
package com.foo;
class Example {
static int a = 1/0;
}
class Main {
public static void main(String[] args) throws Exception {
try {
Class<?> c = Class.forName("com.foo.Example");
} catch (ExceptionInInitializerError e) {
System.err.println("Hey I caught it");
Throwable actualException = e.getCause();
// do something with it here
actualException.printStackTrace(); // not this - this is for debugging only!
}
}
}