Sunday, February 1, 2009

Java Exceptions usage

I'm working on project which definitely requires Exception re-architecture and I had a quick discussion about that topic with my colleagues. That discussion was the trigger which activated some parts of my brain and materialized into that post. Some ideas can be arguable, so comments are much appreciated.

It looks like, there is big misunderstanding on how to use checked and unchecked exceptions and what exactly is the difference between them. Assume that misunderstanding was born from the fact that developers ignore fact that Java's error processing is based on Exceptions. That fact means that each piece of code can throw exception anytime, whether declared it explicitly or not. Which means, that you do not need to to declare exception explicitly to make developer think, that exception can be thrown - he has to assume it anyway.

So rule is quite simple - unchecked exceptions are for system errors, checked exceptions are for business ones. Business errors are errors, which can happen as a result of EXPECTED business conditions, like UserNotFoundException. Business code has to make a decision based on caught exception and usually it will affect of execution flow. If such exception is thrown, it means, that system behaves as it is expected to behave.
On opposite unchecked exception is something, which is NOT expected, so in the most of the cases, developer should not throw such exceptions by himself. There are just a few possible cases when developer can throw then - converting of checked system exceptions (like, java.io.IOException which is checked for some uknown reason) or throwing exceptions on "assertion" checks, e.g. throwing java.lang.IllegalArgumentException for invalid argument value, etc. Such exceptions are are consequence of system and technical failures, which are not part of business flow.

There is opinion which says that it's a bad practice to log exception on every catch. Well, that's clean and gives some economy of disk space, but has one big disadvantage - it doesn't give you guarantee, that exception will be logged at all. So, better approach is logging exception each time it is caught. Yes, it will add some trash (not much, of case of good architecture) in logs, but usually applications do not have many catch statements (again, in case when they are designed properly :) see next paragraph). Some more stack traces shouldn't confuse anyone. It gives bigger confidence, that exceptions will be logged, at least by your code, even if client code will swallow it. For production systems such confidence is much more important than clean logs.

To make logs and logic cleaner, if you are not interested in exception - do not to catch it at all. Business Exceptions are, usually, are part of business logic and should be processed appropriately, code usually is interested in them. But there is no point in catching Runtime (unexpected) exceptions, which should be caught just by the top-most, application layer and just only to log it and display "Sorry" page to user.
But is doesn't mean, that you shouldn't worry about writing exception-safe code and do not use try-finally construction, which are amust even if it looks that code will not ever throw exception.
Sometimes there are such cases like IOException, which, unluckily, is not checked. Most propably, you may not want to add it into "throws" list. I think that the best you can do is to wrap it with custom non-checked exception and re-throw.

2 comments:

phil pirj said...

I completely agree that IOEx should be Runtime, not the part of business logic. Catching them and rethrowing is just undrying of code, usually managed by young staff as a "if there's a chance it can fail and Ex will be thrown, let's to catch it, log it' rethrow it...ten fuckn times'
If a checked exception is being thrown, the best way to cat it is a a dispatcher level, with full stacktrace. There's no way to recover anyway...

phil pirj said...

forgot to set follow-up on updates on all my replies
hope people send a personal glossy copy of their comments to me if ever ;)