If you’re working with Spring, check out "REST With Spring":


1. Overview

In Java, the sneaky throw concept allows us to throw any checked exception without defining it explicitly in the method signature. This allows the omission of the throws declaration, effectively imitating the characteristics of a runtime exception.

In this article, we’ll see how this is done in practice, by looking at some code examples.

2. About Sneaky Throws

Checked exceptions are part of Java, not the JVM. In the bytecode, we can throw any exception from anywhere, without restrictions.

Java 8 brought a new type inference rule that states that a throws T is inferred as RuntimeException whenever allowed. This gives the ability to implement sneaky throws without the helper method.

A problem with sneaky throws is that you probably want to catch the exceptions eventually, but the Java compiler doesn’t allow you to catch sneakily thrown checked exceptions using exception handler for their particular exception type.

3. Sneaky Throws in Action

As we already mentioned, the compiler and the Jave Runtime can see different things:

public static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
    throw (E) e;

private static void throwsSneakyIOException() {
    sneakyThrow(new IOException("sneaky"));

The compiler sees the signature with the throws T inferred to a RuntimeException type, so it allows the unchecked exception to propagate. The Java Runtime doesn’t see any type in the throws as all throws are the same a simple throw e.

This quick test demonstrates the scenario:

public void whenCallSneakyMethod_thenThrowSneakyException() {
    try {
    } catch (Exception ex) {
        assertEquals("sneaky", ex.getMessage().toString());

It’s possible to throw a checked exception using bytecode manipulation, or Thread.stop(Throwable), but it’s messy and not recommended.

4. Using Lombok Annotations

The @SneakyThrows annotation from Lombok allows you to throw checked exceptions without using the throws declaration. This comes in handy when you need to raise an exception from a method within very restrictive interfaces like Runnable.

Say we throw an exception from within a Runnable; it will only be passed to the Thread’s unhandled exception handler.

This code will throw the Exception instance, so there is no need for you to wrap it in a RuntimeException:

public class SneakyRunnable implements Runnable {
    public void run() {
        throw new InterruptedException();

A drawback with this code is that you cannot catch a checked exception that is not declared; so, it will not compile.

Here’s the correct form for throwing a sneaky exception:

public void run() {
    try {
        throw new InterruptedException();
    } catch (InterruptedException e) {

And here’s the test for this behavior:

public void whenCallSneakyRunnableMethod_thenThrowException() {
    try {
        new SneakyRunnable().run();
    } catch (Exception e) {
        assertEquals(InterruptedException.class, e.getStackTrace());

5. Conclusion

As we have seen in this article, the Java compiler can be tricked to treat checked exceptions as unchecked.

As always the code is available over on GitHub.

The new Certification Class of "REST With Spring" is finally out:


Leave a Reply

2 Comments on "“Sneaky Throws” in Java"

Notify of
Sort by:   newest | oldest | most voted
Volkan Yazici
I agree with the fact that checked exceptions can (and generally do) pollute the code with unnecessary try/catch blocks. Though I also do not like sneaky throws since you lose the context where the exception was sneakily thrown, which makes it almost impossible to pinpoint exceptions by looking at the stack trace logs. My personal approach on sanitizing methods throwing checked exceptions is to wrap them in a RuntimeException in the first place they occur. This way you can still keep your code clean (together with your peace of mind) and track down stack traces in the logs. What about… Read more »
Grzegorz Piwowarek

Well, totally agree – the concept of sneaky throws is not for everyday use but showcases an interesting aspect of type inference rules introduced with Java 8