Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rethrowing Exception without requiring throws Exception? [duplicate]

Tags:

java

Consider the following code:

static void main(String[] args) {
  try {
  } catch (Exception e) {
    throw e;
  }
}

This code compiles without having to add throws Exception to the method signature. (It behaves similarly with Throwable in place of Exception, too).

I understand why it can be run safely, in that Exception can't actually be thrown in the try block, so a checked exception cannot be thrown; I'm interested to know where this behaviour is specified.

It's not simply that the throw e is never reached: the following code also compiles:

static void stillCompilesWithThrownUncheckedException() {
  try {
    throw new NullPointerException();
  } catch (Exception e) {
    throw e;
  }
}

But if you throw a checked exception, it doesn't compile, as I expect:

static void doesNotCompileWithThrownCheckedException() {
  try {
    throw new Exception();
  } catch (Exception e) {
    throw e;  // error: unreported exception Exception; must be caught or declared to be thrown
  }
}

In JLS Sec 11.2.2, it says:

A throw statement (§14.18) whose thrown expression has static type E and is not a final or effectively final exception parameter can throw E or any exception class that the thrown expression can throw.

My interpretation of this statement is that throw e can throw Exception, because the static type of e is Exception. And then, in JLS Sec 11.2.3:

It is a compile-time error if a method or constructor body can throw some exception class E when E is a checked exception class and E is not a subclass of some class declared in the throws clause of the method or constructor.

But it's not a compile-time error in the first two cases. Where is this behavior described in the language spec?


Edit: having marked it a dupe, I was going to ask the follow-up question: why isn't throw e; considered unreachable in the first example.

The answer was much easier to find in JLS Sec 14.21:

  • A catch block C is reachable iff both of the following are true:

    • Either the type of C's parameter is an unchecked exception type or Exception or a superclass of Exception, or some expression or throw statement in the try block is reachable and can throw a checked exception whose type is assignable to the type of C's parameter. (An expression is reachable iff the innermost statement containing it is reachable.)

      See §15.6 for normal and abrupt completion of expressions.

    • There is no earlier catch block A in the try statement such that the type of C's parameter is the same as or a subclass of the type of A's parameter.

Both of these are true (it's of type Exception, and there's no earlier catch block), so it's "reachable". I guess the effort of calling out an empty try block as a special case was too great for such a marginally-useful construct.

like image 551
Andy Turner Avatar asked Oct 29 '25 08:10

Andy Turner


1 Answers

I believe the very next paragraph of section 11.2.2 answers the question:

A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:

  • E is an exception class that the try block of the try statement which declares C can throw; and

So, throw e; “can throw” only exceptions which the corresponding try-block “can throw,” where the latter is defined by the actual statements in the try-block.

Obviously an empty try-block does not qualify as a “can throw” section for any exception class. Your second example “can throw” NullPointerException, and since the catch-block “can throw” only the exception that the try-block “can throw,” the catch-block too can throw only the unchecked NullPointerException.

Your third example’s try-block “can throw” java.lang.Exception itself, therefore the catch-block “can throw” java.lang.Exception, so java.lang.Exception must be caught or declared to be thrown.

like image 118
VGR Avatar answered Oct 30 '25 23:10

VGR



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!