As demonstrated by the below test, the following from JLS 15.12.2.6 is not correctly implemented.
"If unchecked conversion was necessary for the method to be applicable then the throws clause is composed of the erasure (4.6) of the types in the method���s declared throws clause."
javac instead applies any provided type arguments to methods and constructors (as if this clause were not present), or, where type arguments are inferred, chooses an unerased thrown type variable. Fortunately, in this latter case, I don't think there's any way to distinguish type "E" from type "erasure of E", so that case only has an impact on error messages (unless I'm wrong).
The correct behavior for constructor invocations is unclear -- I've suggested below what seems the most reasonable and consistent. See also specification bug 7015422.
In my 6u22 compiler, the explicit type argument case behaved the same as the inferred type argument case, so that has since been "fixed," but the fix is not consistent with the JLS.
/**
* Testing the following from JLS 15.12.2.6:
* If unchecked conversion was necessary for the method to be applicable
* then the throws clause is composed of the erasure (4.6) of the types
* in the method���s declared throws clause.
*/
public class UncheckedInvocation {
static <E extends Exception> Iterable<E> empty(Iterable<E> arg) throws E {
for (E e : arg) throw e;
return arg;
}
<E extends Exception> UncheckedInvocation(Iterable<E> arg) throws E {
empty(arg);
}
/**
* Method invocation, no unchecked
* Specified thrown: RuntimeException
* javac: RuntimeException
* Eclipse: RuntimeException
*/
void m1() {
Iterable<RuntimeException> i = java.util.Collections.emptyList();
empty(i);
}
/**
* Method invocation, unchecked, inferred arguments
* Specified thrown: Exception
* javac: E (!)
* Eclipse: Exception
*/
void m2() {
Iterable i = java.util.Collections.EMPTY_LIST;
empty(i);
}
/**
* Method invocation, unchecked, explicit arguments
* Specified thrown: Exception
* javac: RuntimeException
* Eclipse: RuntimeException
*/
void m3() {
Iterable i = java.util.Collections.EMPTY_LIST;
UncheckedInvocation.<RuntimeException>empty(i);
}
/**
* Constructor invocation, no unchecked
* Specified thrown: RuntimeException (unclear)
* javac: RuntimeException
* Eclipse: RuntimeException
*/
void m4() {
Iterable<RuntimeException> i = java.util.Collections.emptyList();
new UncheckedInvocation(i);
}
/**
* Constructor invocation, unchecked, inferred arguments
* Specified thrown: Exception? (unclear)
* javac: E (!)
* Eclipse: Exception
*/
void m5() {
Iterable i = java.util.Collections.EMPTY_LIST;
new UncheckedInvocation(i);
}
/**
* Constructor invocation, unchecked, explicit arguments
* Specified thrown: Exception? (unclear)
* javac: RuntimeException
* Eclipse: RuntimeException
*/
void m6() {
Iterable i = java.util.Collections.EMPTY_LIST;
new <RuntimeException>UncheckedInvocation(i);
}
}