Java SneakyThrow of exceptions, type erasure

If you compile it with -Xlint you'll get a warning:

c:\Users\Jon\Test>javac -Xlint SneakyThrow.java
SneakyThrow.java:9: warning: [unchecked] unchecked cast
    throw (T) ex;
              ^
  required: T
  found:    Throwable
  where T is a type-variable:
    T extends Throwable declared in method <T>sneakyThrowInner(Throwable)
1 warning

That's basically saying "This cast isn't really checked at execution time" (due to type erasure) - so the compiler reluctantly assumes you're doing the right thing, knowing that it won't actually be checked.

Now it's only the compiler which cares about checked and unchecked exceptions - it's not part of the JVM at all. So once you've got past the compiler, you're home free.

I'd strongly advise you to avoid doing this though.

In many cases there's a "real" check when you're using generics because something uses the desired type - but that's not always the case. For example:

List<String> strings = new ArrayList<String>();
List raw = strings;
raw.add(new Object()); // Haha! I've put a non-String in a List<String>!
Object x = strings.get(0); // This doesn't need a cast, so no exception...

he above code seems to mean that finally we can also assign a value of type Cat to a variable of type Dog or something like that.

You have to think in terms of how the classes are structured. T extends Throwable and you are passing Exception to it. This is like assigning Dog to Animal not Dog to Cat.

The compiler has rules about which Throwable are checked and which are not, based on inheritance. These are applied at compile time and it is possible to confuse the compiler into allowing you to throw a check exception. At runtime this has no impact.


Checked exceptions are a compile time feature (like generics)

BTW Throwable is a checked exception as well. If you sub class it, it will be checked unless it is a sub-class of Error or RuntimeException.

Two other way to throw checked exceptions without the compiler being aware that you are doing this.

Thread.currentThread().stop(throwable);

Unsafe.getUnsafe().throwException(throwable);

The only difference is that both use native code.


As of Java 8, the sneakyThrowInner helper method is no longer required. sneakyThrow can be written as:

@SuppressWarnings("unchecked")
static <T extends Throwable> RuntimeException sneakyThrow(Throwable t) throws T {
    throw (T)t;
}

See the "A peculiar feature of exception type inference in Java 8" post.

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)

Note: The sneakyThrow function is declared to return RuntimeException, so that it can be used as follows:

int example() { 
   if (a_problem_occurred) {
      throw sneakyThrow(new IOException("An I/O exception occurred"));
      // Without the throw here, we'd need a return statement!
   } else {
      return 42;
   }
}

By throwing the RuntimeException returned by sneakyThrow, the Java compiler knows this execution path terminates. (Of course, sneakyThrow itself doesn't return.)