Aleksandr Erokhin
Aleksandr Erokhin

Reputation: 1982

Rethrowing RuntimeException as Exception

Java allows me to compile the following code without any issues:

public class Test {
    public static void main(String[] args){
        try {
            throw new RuntimeException();
        } catch (Exception e) {
            throw e;
        }
    }
}

Even though java.lang.Exception is a checked exception. Meaning that I am rethrowing unchecked exception as checked and get away with that.

Most likely Java compiler is able to figure out that no checked exception is thrown in the try block, but I can't find the section in the specification that backups that.

Can one rely on this behavior and starting from which JDK version?

Update: This class doesn't compile with Java 1.6.0_38 with the following message:

Test.java:6: unreported exception java.lang.Exception; must be caught or declared to be thrown
            throw e;
            ^
1 error

Upvotes: 2

Views: 526

Answers (2)

Stephen C
Stephen C

Reputation: 719426

The part of the Java Language Specification that governs this can be found in JLS 11.2.2

11.2.2. Exception Analysis of Statements

...

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

  • E is assignment compatible with any of C's catchable exception classes; and

  • E is not assignment compatible with any of the catchable exception classes of the catch clauses declared to the left of C in the same try statement.

When E is RuntimeException 1) E can be thrown in the try block, 2) the catch clause can catch it, and 3) there are no catch clauses "to the left". Therefore the throw in the catch clause can throw RuntimeException.

On the other hand, E is Exception, E cannot be thrown in the try block. Therefore the throw in the catch clause cannot throw Exception.

Upvotes: 0

Aleksandr Erokhin
Aleksandr Erokhin

Reputation: 1982

It looks like that this is one of the effects of the enhancement in Java 7: Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking. See section "Rethrowing Exceptions with More Inclusive Type Checking."

The Java SE 7 compiler can determine that the exception thrown by the statement throw e must have come from the try block, and the only exceptions thrown by the try block can be FirstException and SecondException. Even though the exception parameter of the catch clause, e, is type Exception, the compiler can determine that it is an instance of either FirstException or SecondException.

Please note, that the following will not compile though even in Java 7 and above:

public class Test {
    public static void main(String[] args){
        try {
            throw new RuntimeException();
        } catch (Exception e) {
            Exception e1 = e;
            throw e1;
        }
    }
}

Because:

This analysis is disabled if the catch parameter is assigned to another value in the catch block.

Upvotes: 2

Related Questions