Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Wicked Trick to Make the JVM Forget to Check Exceptions

DZone's Guide to

A Wicked Trick to Make the JVM Forget to Check Exceptions

Let's take a lesson from Lombok and Java's type erasure to convince the JVM to just let exceptions go. Meanwhile, we can learn a few things about the JVM's internals.

· Java Zone ·
Free Resource

Distribute microservices between the private and public clusters, yet maintain bi-directional connectivity. Content provided by IBM Developer.

I’ve been a long-time been critic of the mechanism of compiler-checked exceptions in Java. Whether you love them or hate them, one thing is sure: There are situations where you don’t want to have to deal with them. The solution in Java is to wrap a checked exception in a new RuntimeException, but this gives long stack traces without adding useful information. Sometimes, we just want to tell the compiler to chill.

As it turns out, this is possible through some wicked abuse of the type erasure misfeature of Java generics. Seeing this in action is instructive for understanding the inner workings of Java. Let’s go!

Here is what we want:

public static void main(String[] args) {
    businessLogic();
}

private static void businessLogic() {
    List < String > configuration = readConfigurationFile();
    System.out.println(configuration.get(0));
}

private static List < String > readConfigurationFile() {
    try {
        return Files.readAllLines(Paths.get("non", "existing", "file"));
    } catch (IOException e) {
        throw softenException(e);
    }
}


Notice that the businessLogic() neither catches IOException nor declares that it throws IOException. Instead, the softenException() method removes the checkedness of the exception. When we run it, we get the following stack trace:

Exception in thread "main" java.nio.file.NoSuchFileException: non\existing\file
	at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
	at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
	at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
	at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230)
	at java.nio.file.Files.newByteChannel(Files.java:361)
	at java.nio.file.Files.newByteChannel(Files.java:407)
	at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)
	at java.nio.file.Files.newInputStream(Files.java:152)
	at java.nio.file.Files.newBufferedReader(Files.java:2784)
	at java.nio.file.Files.readAllLines(Files.java:3202)
	at java.nio.file.Files.readAllLines(Files.java:3242)
	at insanejava.SoftenExceptionsDemo.readConfigurationFile(SoftenExceptionsDemo.java:21)
	at insanejava.SoftenExceptionsDemo.businessLogic(SoftenExceptionsDemo.java:15)
	at insanejava.SoftenExceptionsDemo.main(SoftenExceptionsDemo.java:11)


Huh! The exception being thrown in the main method is a NoSuchFileException, which is a subclass of IOException – a checked exception! How can that be? Why didn’t any of the methods in the program have to declare throws IOException?

Here’s the trick:

private static RuntimeException softenException(Exception e) {
    return checkednessRemover(e);
}

private static < T extends Exception > T checkednessRemover(Exception e) throws T {
    throw (T) e;
}


The checkednessRemover method uses a trick that reveals a few things about the inner workings of Java. First, the generic type argument T is bound to RuntimeException in order to fulfill the contract of softenException. This means that the expression throws T becomes throws RuntimeException, which the compiler interprets as if there were no exceptions thrown.

But the statement throw (T)e; theoretically should evaluate to throw (RuntimeException)e;. Since e is a NoSuchFileException, you would expect this statement to result in a ClassCastException. But the way generics work in Java, the type information is removed by the compiler. So instead, the bytecode reads as throw (Exception)e;, which is fine.

So this strange trick shows that the Java compiler removes generic information from the compiled code and that checked exceptions are purely a feature of the compiler. There are no runtime verifications of checked exceptions.

Would I recommend using this trick in production code? I don’t know. It’s pretty weird and may not be that useful, but I do use it myself when I’m feeling wicked. If nothing else, I hope learning about this has given you some insights into the inner workings of Java.

Disclaimers: (1) I read about this trick somewhere else, but I cannot find the source any longer. I thought it was Heinz Kabutz’ excellent Java Specialist newsletter, but I can’t find the source. (2) This is also implemented in Project Lombok as @SneakyThrows. If you are using Lombok, you should under no circumstance reimplement the trick from this blog. Use @SneakyThrows instead.

Use this tool to look at the contents of GitHub and classify code based on the programming language used.  Content provided by IBM Developer.

Topics:
java ,jvm ,exception handling ,compiler

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}