aliteralmind
aliteralmind

Reputation: 20163

Why can't you call initCause with an ExceptionInInitializerError?

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

Answers (1)

aliteralmind
aliteralmind

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

Related Questions