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. (?)
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 acatch
clause C can throw an exception class E iff:
- E is an exception class that the
try
block of thetry
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 sametry
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!