Throwing Checked Exceptions Like Unchecked Exceptions in Java
Everyone who’s programming Java knows checked exceptions. You only can throw a checked exception when you’ve declare it. And you have to catch an checked exception, no matter whether it actually can occur.
First my opinion: I think check exception are a failure. The intention was good, but in practice they cause pain, boilerplate-code and in general cause more problems than they solve.
So in my code I avoid checked exceptions. Unfortunately the existing JAVA-API’s are littered with checked exceptions. So I still need to deal with them. The usual strategy looks like this:
try{ someObject.doOperation(); } catch(OperationException e){ throw new RuntimeException("See inner exception",e); }
This works fine, but fills up the stack-trace with unnecessary garbage. (grey= garbage, black= important). And because you normally have multiple such rethrow-blocks in your code, the cause is nested somewhere in a huge stack trace:
Exception in thread "main" java.lang.RuntimeException: See inner exception
at ch.gamlor.test.ExceptionBlogPost.methodWithoutCheckedException(ExceptionBlogPost.java:27)
at ch.gamlor.test.ExceptionBlogPost.openSimulation(ExceptionBlogPost.java:20)
at ch.gamlor.test.ExceptionBlogPost.demostrateStackTrace(ExceptionBlogPost.java:15)
at ch.gamlor.test.ExceptionBlogPost.main(ExceptionBlogPost.java:11)
Caused by: ch.gamlor.test.OperationFailedException: Could not find appropriate example
at ch.gamlor.test.ExceptionBlogPost.legacyMethodWithCheckedExceptions(ExceptionBlogPost.java:32)
at ch.gamlor.test.ExceptionBlogPost.methodWithoutCheckedException(ExceptionBlogPost.java:25)
... 3 more
The Hack
Now recently I’ve discovered this post on StackOverflow, about unknown ‘features’ of the Java language. There someone showed how to throw checked exception without declaring them. Basically he combines the exception with generics and misuses the type erasure of the compiler, so that the type of the exception is erased =). Btw. the post includes another surprise: You can declare a class in methods =).
Here’s the code and more details how it works:
public final class UncheckedThrow { private UncheckedThrow(){} public static void throwUnchecked(final Exception ex){ // Now we use the 'generic' method. Normally the type T is inferred // from the parameters. However you can specify the type also explicit! // Now we du just that! We use the RuntimeException as type! // That means the throwsUnchecked throws an unchecked exception! // Since the types are erased, no type-information is there to prevent this! UncheckedThrow.<RuntimeException>throwsUnchecked(ex); } /** * Remember, Generics are erased in Java. So this basically throws an Exception. The real * Type of T is lost during the compilation */ public static <T extends Exception> void throwsUnchecked(Exception toThrow) throws T{ // Since the type is erased, this cast actually does nothing!!! // we can throw any exception throw (T) toThrow; } }
Now you just can use this method to ‘rethrow’.:
try{ legacyMethodWithCheckedExceptions(); } catch (OperationFailedException e){ UncheckedThrow.throwUnchecked(e); }
And surprisingly this works! And even better, no rethrow-garbage, and also the throw location is right!
Exception in thread "main" ch.gamlor.test.OperationFailedException: Could not find appropriate example ;) at ch.gamlor.test.ExceptionBlogPost.legacyMethodWithCheckedExceptions(ExceptionBlogPost.java:32) at ch.gamlor.test.ExceptionBlogPost.methodWithoutCheckedException(ExceptionBlogPost.java:25) at ch.gamlor.test.ExceptionBlogPost.openSimulation(ExceptionBlogPost.java:20) at ch.gamlor.test.ExceptionBlogPost.demostrateStackTrace(ExceptionBlogPost.java:15) at ch.gamlor.test.ExceptionBlogPost.main(ExceptionBlogPost.java:11)
Fine Tuning The Hack
Now we’re facing the next problem. Supposed we’ve a method which returns a value and we use out little hack. Then we’ve a problem. Since the compiler doesn’t see the ‘exception’, it requires you to return something or throw something. Well that’s easy to fix. Change the signature from void to RuntimeException, so that you can throw it. But the implementation never actually returns, but throws the suppress checked exception.
public final class UncheckedThrow { private UncheckedThrow(){} // Now this returns an exception, so that you can satisfy the compiler by throwing it. // But in reality we throw the given exception! public static RuntimeException throwUnchecked(final Exception ex){ // Now we use the 'generic' method. Normally the type T is inferred // from the parameters. However you can specify the type also explicit! // Now we du just that! We use the RuntimeException as type! // That means the throwsUnchecked throws an unchecked exception! // Since the types are erased, no type-information is there to prevent this! UncheckedThrow.<RuntimeException>throwsUnchecked(ex); // This is here is only to satisfy the compiler. It's actually unreachable code! throw new AssertionError("This code should be unreachable. Something went terrible wrong here!"); } /** * Remember, Generics are erased in Java. So this basically throws an Exception. The real * Type of T is lost during the compilation */ public static <T extends Exception> void throwsUnchecked(Exception toThrow) throws T{ // Since the type is erased, this cast actually does nothing!!! // we can throw any exception throw (T) toThrow; } }
Now you can use it anywhere!
private int methodWithoutCheckedException() { try{ return legacyMethodWithCheckedExceptions(); } catch (OperationFailedException e){ throw UncheckedThrow.throwUnchecked(e); } }
It’s not only limited to rethrows, you can throw a checked exception anywhere. However I think that’s a very bad idea!
private String demoJustThrow(){ throw UncheckedThrow.throwUnchecked(new IOException("See, I'm not declared")); }
Conclusion
I’ve demonstrated how to throw checked exception like unchecked ones. Yes, this is certainly a real evil hack. However I also think that avoiding unnecessary garbage in stack traces is a real benefit. So I’ve started to use this for rethrowing checked exceptions in my projects.
I’ve also to mention that this could be a weakness in the javac-compiler. I haven’t checked this against the language definition =).
The source-file is here. Try it yourself: UncheckedThrow.java
- The Way of the Whiteboard, Modern Hardware, Writing DSLs with LINQ and Component Relationships
- What Am I Working On?
Amazing feature something java desperately needed and an answer to all those questions related to checked exception polluting java codes. I have never been a big fan of checked Exceptions and prefer RuntimeException due to same reason but looks like after 6 version Java guys are making some progress in this direction.