2

JLS 11.2.3 says that it is a compile time error if a method body can throw a checked exception and it does not declare the class (or a parent class) in its throws clause. In the following code, Throwable is a checked exception (per JLS 11.1.1) being thrown in the catch clause of main:

public class Main {
  public static void main(String[] args) {
    try {
      foo();
    } catch (Throwable t) {
      throw t;
    }
  }

  public static void foo() {
    throw new RuntimeException();
  }
}

However, javac compiles it without any errors. If we change the signature of foo to declare that it throws Throwable, we get an error as expected:

public class Main {
  public static void main(String[] args) {
    try {
      foo();
    } catch (Throwable t) {
      throw t;
    }
  }

  public static void foo() throws Throwable {
    throw new RuntimeException();
  }
}
$ javac Main.java
Main.java:6: error: unreported exception Throwable; must be caught or declared to be thrown
      throw t;
      ^
1 error

It seems like javac figures out (in the first example) that, since foo does not declare any checked exceptions, the caught Throwable t must be an unchecked exception, and so main only ever rethrows an unchecked exception, and thus it does not need a throws clause. Is there anything in the JLS that explains this behaviour?

Johannes Kuhn
  • 14,778
  • 4
  • 49
  • 73
MattDs17
  • 401
  • 1
  • 4
  • 20
  • No, @MattDS18 is correct, the behaviour is odd. In the first example, the main method is throwing an exception whose static type is Throwable, which is a checked exception, and therefore should give rise to a unreported exception compiler error, but it doesn't. The even more odd thing is, if you cast it to a Throwable (i.e. `throw (Throwable)t` then the compiler will (correctly) complain, even though you haven't actually changed its static type. – jon hanson May 04 '23 at 21:35
  • @jon-hanson an intersting thing happens when you declare `public static void foo() throws IOException` because now the Java Compiler says "error: unreported exception **IOException**; must be caught or declared to be thrown" which shows that the compiler exactly knows what exception can be thrown there. – Thomas Kläger May 05 '23 at 08:24
  • IThe compiler is evidently performing some static analysis. My guess is that if there is no exception decleration on the method, then it infers the only possible exception being caught is Error, which is unchecked. If you add a throws Throwable (or any other checked exception) then it gives rise to the expected compiler error as Throwable is checked. – jon hanson May 05 '23 at 08:28
  • 1
    @jon-hanson the compiler checks which exceptions can be thrown in the `try` block. No guess needed, the feature is in the Java 7 release notes: [Rethrowing Exceptions with More Inclusive Type Checking](https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html#rethrow) – Thomas Kläger May 05 '23 at 08:36

0 Answers0