Checked exceptions are a feature of the Java language and only enforced by the compiler. They are not enforced by the Java virtual machine whatsoever.
The throws clause is still recorded in a compiled class file for sake of programming against a compiled library. But in describing the meaning of the data, the JVM spec notes that:
These requirements are not enforced in the Java Virtual Machine; they are enforced only at compile time.
There are various ways to bypass exception checking, such as by abusing generics (which are erased at run time and not fully checked):
class Example {
public static void main(String[] args) {
sneakyThrow(new java.io.IOException());
}
public static void sneakyThrow(Throwable t) {
Example.<RuntimeException>sneakyThrow0(t);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow0(Throwable t) throws T {
throw (T)t;
}
}
Output:
Exception in thread "main" java.io.IOException
at Example.main(Example.java:3)
Also, the reflection method Class.newInstance() is deprecated because due to a design flaw, it rethrows any checked exception thrown by the class's constructor, without wrapping or declaring it:
Deprecated.
This method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler.