Reputation: 743
What is happening here?
Why checked child of IOException (RemoteException) gets converted to RuntimeException?
Snippet taken from here
import java.rmi.RemoteException;
class Thrower {
public static void spit(final Throwable exception) {
class EvilThrower<T extends Throwable> {
@SuppressWarnings("unchecked")
private void sneakyThrow(Throwable exception) throws T {
throw (T) exception; // something interesting
}
}
new EvilThrower<RuntimeException>().sneakyThrow(exception);
}
}
public class ThrowerSample {
public static void main( String[] args ) {
Thrower.spit(new RemoteException("go unchecked!"));
}
}
Upvotes: 0
Views: 558
Reputation: 8307
What is happening here?
This code circumvents Compile-Time Checking of Exceptions.
It is not always convenient to work with api that uses checked exceptions.
One of the most famous examples is JDBC. Working with jdbc always requires the developer to deal with SQLException
. But usually you don't know what you should do with the exception.
Or if you're working with library where the developers decided to inherit their exceptions from Exception
rather than RuntimeException
.
IOException
(RemoteException
) gets converted to RuntimeException
?It is not converted to a RuntimeException
.
The thrown exception is RemoteException
:
Exception in thread "main" java.rmi.RemoteException: go unchecked!
The code snippet uses Java generics "tricks". Without the @SuppressWarnings("unchecked")
line the compiler would generate an unchecked cast warning.
The code snippet is one of the solutions of Puzzle 43 of Java Puzzlers: Traps, Pitfalls, and Corner Cases:
// Don’t do this - circumvents exception checking!
public static void sneakyThrow(Throwable t) {
Thread.currentThread().stop(t); // Deprecated!!
}
It is possible to write a method that is functionally equivalent to
sneakyThrow
without using any deprecated methods. In fact, there are at least two ways to do it. One of them works only in release 5.0 and later releases. Can you write such a method? It must be written in Java, not in JVM bytecode. You must not change the method after its clients are compiled. Your method doesn’t have to be perfect: It is acceptable if it can’t throw one or two subclasses ofException
.
Solution from the book using generics:
// 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;
}
}
Note on this solution from the book:
A warning is the compiler’s way of telling you that you may be shooting yourself in the foot, and in fact you are. The unchecked cast warning tells you that the cast in question will not be checked at run time. When you get an unchecked cast warning, modify your program to eliminate it, or convince yourself that the cast cannot fail
In summary, Java’s exception checking is not enforced by the virtual machine. It is a compile-time facility designed to make it easier to write correct programs, but it can be circumvented at run time. To reduce your exposure, do not ignore compiler warnings.
Upvotes: 3