1

Given the program following:

class FirstException extends Exception {}

class SecondException extends Exception {}

class RethrowException {
     public void rethrowMethod() throws FirstException, SecondException {
          boolean flag = true;
          try {
              if(flag)
                  throw new FirstException();
              else
                  throw new SecondException(); 
          }
          catch(Exception ex) {
              throw ex;   // does not compile "Unhandled exception type Exception" 
          }
     }
}

This error just happens with Java SE 6 (or prior versions) because firstly, when we build the "catch" block (catch(Exception ex)), the exception object, specified by ex, has the type of FirstException (or SecondException). But, when ex is re-thrown (throw ex), the Java compiler performs 3 tasks as follows:

  1. Release "ex" to system.
  2. Initialization new exception object, "ex" that has the type of Exception
  3. Throw "ex" - that is instance of Exception, right now, not instance of FirstException (or SecondException)

Thus, in the Java SE 6, we cannot use "more precisely rethrow exception" because the reason following. However, in the Java SE 7 (or later), we can do that, because when we re-throw ex, the runtime system does not release and initialize new object ex. It will check (find) where ex1 come from (the try block above), and so know thatexis an instance ofFirstExceptionorSecondException`.

My explanation above is correct or not?

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • I can't tell what part of this is your explanation and what part is the question. – T.J. Crowder Oct 28 '17 at 14:42
  • I *can* tell you that the answer to "why can I compile this on Java 7 or higher but not Java 6 or lower" (if indeed that's the case) won't have anything to do with *runtime* behavior. It'll have to do with the *compiler* having got more intelligent. – T.J. Crowder Oct 28 '17 at 14:43
  • 1
    Does this really compile in Java >6? It looks like a bad practice to me.. Edit: It does, I see this example comes from the Java documentation [link](https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html). – NickL Oct 28 '17 at 14:46
  • 1
    @NickL: Yes, it does. The compiler knows the types of the exceptions that can be thrown in the block, and knows we're rethrowing rather than throwing a new one. – T.J. Crowder Oct 28 '17 at 14:49

1 Answers1

4

No new exception instance is created by catching the exception and throwing it from the catch block, in any version on Java.

In Java 6-, the type of the caught exception is declared as Exception by the catch block, so that is what the compiler thinks is being thrown.

In later versions, the type of the exception was inferred to be bounded to only what could be thrown from the try block.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • I don't understand, when I check the type of "ex" (using instanceof), I get "FirstException". So, "ex" has the type of FirstException, why when we rethrown, the runtime system will throw Exception type, while it is FirstException? – John Minverva Oct 28 '17 at 14:57
  • @John `instanceof` is a *runtime* thing. The error is a *compile time* thing. The compiler is stupid. It doesn't reason out what something could be, it only looks at what it's *declared* as. Java 7+ is slightly smarter in this situation. – Bohemian Oct 28 '17 at 14:59
  • can I summarize this: "In Java SE 6-, the compiler does not care about everything happens before rethrowing. So, whe "ex" is rethrown, the compiler will throw Exception (it looks at what's "ex" declared as), although, actually, "ex" is FirstException...Is it right?? – John Minverva Oct 28 '17 at 15:07
  • @John no. The compiler does't rethrow anything; it just compiles. The runtime JVM rethrows the instance of Exception that was caught. The issue is in Java 6- the compiler works only with the type declared to be caught, ie `Exception ex` tells the compile that `ex` has a type of `Exception`, but the method is only declared to throw 2 specific subtypes on `Exception`, hence the error. – Bohemian Oct 28 '17 at 15:08
  • 1
    Do you have a JLS reference handy? I tried to find where this behaviour is described but haven't been able to yet. – Erwin Bolwidt Oct 28 '17 at 15:45
  • 2
    @ErwinBolwidt The documentation (where OP got the example from) describes this behaviour([link](https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html)). I think [this](https://docs.oracle.com/javase/specs/jls/se7/html/jls-11.html#jls-11.2) is the relevent JLS part "We say that a statement or expression can throw a checked exception class E if, according to the rules in §11.2.1 and §11.2.2, the execution of the statement or expression can result in an exception of class E being thrown.". – NickL Oct 28 '17 at 17:55
  • @NickL Any ideas of what changed between Java 6 and Java 7 in the JLS regarding this? See also my question here: https://stackoverflow.com/q/58416402/1310566 – Simon Forsberg Oct 16 '19 at 15:19
  • 1
    @SimonForsberg, they added the whole multi-catch syntax in Java7, I believe, which meant compiler has to inspect what the `try` block actually might throw, and produce (or not) errors accordingly. If it sees that `try` only throws `IOException`, it's allowed to rethrow even the `Throwable` from the same catch block, and inferred exception type is narrowed to `IOException` regardless. This is how it behaves, to some extent. – M. Prokhorov Oct 16 '19 at 15:39