Reputation: 20163
Why does calling initCause
with an ExceptionInInitializerError
result in an IllegalStateException
?.
public class Test {
public static final void main(String[] ignored) {
try {
ExceptionInInitializerError err = new ExceptionInInitializerError("1. Fail!");
err.initCause(new NullPointerException("null!"));
throw err;
} catch(Exception x) {
x.printStackTrace();
}
System.out.println();
try {
IllegalStateException isx = new IllegalStateException("2. Fail!");
isx.initCause(new NullPointerException("null!"));
throw isx;
} catch(Exception x) {
x.printStackTrace();
}
System.out.println();
try {
throw new IllegalStateException("3. Fail!", new NullPointerException("null!"));
} catch(Exception x) {
x.printStackTrace();
}
}
}
Output:
java.lang.IllegalStateException: Can't overwrite cause with java.lang.NullPointerException: null!
at java.lang.Throwable.initCause(Throwable.java:456)
at Test.main(Test.java:5)
Caused by: java.lang.ExceptionInInitializerError: 1. Fail!
at Test.main(Test.java:4)
java.lang.IllegalStateException: 2. Fail!
at Test.main(Test.java:14)
Caused by: java.lang.NullPointerException: null!
at Test.main(Test.java:15)
java.lang.IllegalStateException: 3. Fail!
at Test.main(Test.java:24)
Caused by: java.lang.NullPointerException: null!
... 1 more
I see nothing in the documentation, for the constructor or for the class itself, that either says (a) it is not allowed, or (b) why it's not allowed. I do see the "There is no saved throwable object."
in the JavaDoc, but, to me, it means that one could be set.
Is this "just because", or is there a reason behind why you can't set the cause for ExceptionInInitializerError
?
Upvotes: 1
Views: 1097
Reputation: 20163
As I was researching this question, I was looking through the source code for ExceptionInInitializerError
.
First, there's this in the class JavaDoc:
As of release 1.4, this exception has been retrofitted to conform to the general purpose exception-chaining mechanism. The "saved throwable object" that may be provided at construction time and accessed via the getException() method is now known as the cause, and may be accessed via the Throwable.getCause() method, as well as the aforementioned "legacy method."
There's nothing about "don't use initCause
", but this seems to be the closest you're going to get.
The constructors explicitely make this impossible, and the internal comments are much clearer than anything in the JavaDoc (which only says "There is no saved throwable object"):
/**
<P>... There is no saved throwable object.</P>
**/
public ExceptionInInitializerError() {
initCause(null); // Disallow subsequent initCause
}
public ExceptionInInitializerError(Throwable thrown) {
initCause(null); // Disallow subsequent initCause
this.exception = thrown;
}
public ExceptionInInitializerError(String s) {
super(s);
initCause(null); // Disallow subsequent initCause
}
Don't quite understand the why really, but it seems to be a mixture of being legacy code that can't be retrofitted, and "just because".
Upvotes: 2