Java Reference
In-Depth Information
class's parameterless constructor. Therefore, the
sneakyThrow
method stashes this exception in a
static variable. To make the method thread-safe, it must be synchronized. This causes concurrent
invocations to take turns using the static
t
field.
Note that the
t
field is nulled out in a
finally
block: Just because the method is sneaky doesn't
mean it should also be leaky. If this field weren't nulled out, it would prevent the exception from
being garbage collected. Finally, note that the method will fail with an
IllegalArgumentException
if you ask it to throw an
InstantiationException
or
IllegalAccessException
. This is an
inherent limitation of the technique.
The documentation for
Class.newInstance
goes on to say that "the
Constructor.newInstance
method avoids this problem by wrapping any exception thrown by the constructor in a (checked)
InvocationTargetException
." Clearly,
Class.newInstance
should have done the same thing, but
it's far too late to correct this deficiency. Doing so would introduce a source-level incompatibility,
breaking the many programs that depend on
Class.newInstance
. It would not be practical to
deprecate this method either, because it is so commonly used. Just be aware when you use it that
Class.newInstance
can throw checked exceptions that it does not declare.
Generics, which were added in release 5.0, enable a completely different solution to this puzzle. For
maximal compatibility generics are implemented by
type erasure
:
Generic type information is
checked at compile time but not at run time
[JLS 4.7]. The following solution exploits this:
// Don't do this either - circumvents exception checking!
class TigerThrower<T extends Throwable> {
public static void sneakyThrow(Throwable t) {
new TigerThrower<Error>().sneakyThrow2(t);
}
private void sneakyThrow2(Throwable t) throws T {
throw (T) t;
}
}
This program will generate a warning when you compile it:
TigerThrower.java:7: warning: [unchecked] unchecked cast
Search WWH ::
Custom Search