Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is throwing a checked exception type allowed in this case?

I noticed by accident that this throw statement (extracted from some more complex code) compiles:

void foo() {
    try {

    } catch (Throwable t) {
        throw t;
    }
}

For a brief but happy moment I thought that checked exceptions had finally decided to just die already, but it still gets uppity at this:

void foo() {
    try {

    } catch (Throwable t) {
        Throwable t1 = t;
        throw t1;
    }
}

The try block doesn't have to be empty; it seems it can have code so long as that code doesn't throw a checked exception. That seems reasonable, but my question is, what rule in the language specification describes this behavior? As far as I can see, §14.18 The throw Statement explicitly forbids it, because the type of the t expression is a checked exception, and it's not caught or declared to be thrown. (?)

like image 853
Boann Avatar asked Jul 27 '14 14:07

Boann


People also ask

Why do we need checked exceptions?

“If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.” In this way, we can recover the system by accepting another user input file name.

What does it mean if an exception is checked?

In broad terms, a checked exception (also called a logical exception) in Java is something that has gone wrong in your code and is potentially recoverable. For example, if there's a client error when calling another API, we could retry from that exception and see if the API is back up and running the second time.

Can checked exceptions be thrown?

We can throw either checked or unchecked exceptions. The throws keyword allows the compiler to help you write code that handles this type of error, but it does not prevent the abnormal termination of the program.

Can you throw a checked exception in Java?

Can throw checked and unchecked exceptions. We can declare both types of exceptions using throws clause i.e. checked and unchecked exceptions. But the method calling the given method must handle only checked exceptions. Handling of unchecked exceptions is optional.


2 Answers

This is because of a change that was included in Project Coin, introduced in Java 7, to allow for general exception handling with rethrowing of the original exception. Here is an example that works in Java 7 but not Java 6:

public static demoRethrow() throws IOException {
    try {
        throw new IOException("Error");
    }
    catch(Exception exception) {
        /*
         * Do some handling and then rethrow.
         */
        throw exception;
    }
}

You can read the entire article explaining the changes here.

like image 97
Keppil Avatar answered Sep 20 '22 15:09

Keppil


I think that the wording in §14.18 The throw Statement, that you refer to, is a mistake in the JLS — text that should have been updated with Java SE 7, and was not.

The bit of JLS text that describes the intended behavior is in §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.

The first bullet point is the relevant one; because the catch-clause parameter t is effectively final (meaning that it's never assigned to or incremented or decremented; see §4.12.4 final Variables), throw t can only throw something that the try block could throw.

But as you say, the compile-time checking in §14.18 does not make any allowance for this. §11.2.2 does not decide what's allowed and what's not; rather, it's supposed to be an analysis of the consequences of the various restrictions on what can be thrown. (This analysis does feed back into more-normative parts of the spec — §14.18 itself uses it in its second bullet point — but §14.18 can't just say "it's a compile-time error if it throws an exception it can't throw per §11.2.2", because that would be circular.)

So I think §14.18 needs to be adjusted to accommodate the intent of §11.2.2.

Good find!

like image 43
ruakh Avatar answered Sep 20 '22 15:09

ruakh