简体   繁体   中英

Checked exception is not thrown and turned into RuntimeException

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!"));
    }
}

What is happening here?

This code circumvents Compile-Time Checking of Exceptions .

Why it can be useful?

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 .


Why checked child of 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.

Puzzle 43

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 of Exception .

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.


See also:

@SneakyThrows

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM