The T of sneakyThrow
is inferred to be RuntimeException
. This can be followed from the langauge spec on type inference (http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html)
Firstly, there's a note in section 18.1.3:
A bound of the form throws α
is purely informational: it directs resolution to optimize the instantiation of α so that, if possible, it is not a checked exception type.
This doesn't affect anything, but it points us to the Resolution section (18.4), which has got more information on inferred exception types with a special case:
... Otherwise, if the bound set contains throws αi
, and the proper upper bounds of αi are, at most, Exception
, Throwable
, and Object
, then Ti = RuntimeException
.
This case applies to sneakyThrow
- the only upper bound is Throwable
, so T
is inferred to be RuntimeException
as per the spec, so it compiles. The body of the method is immaterial - the unchecked cast succeeds at runtime because it doesn't actually happen, leaving a method that can defeat the compile-time checked exception system.
nonSneakyThrow
does not compile as that method's T
has got a lower bound of Exception
(ie T
must be a supertype of Exception
, or Exception
itself), which is a checked exception, due to the type it's being called with, so that T
gets inferred as Exception
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…