Sunday, February 22, 2009

Memory mapped files in Java? Easy!?

Heh. Not so easy :) In NIO there is ability to work with memory mapped files, which is provided via java.nio.MappedByteBuffer. I was really happy with idea using memory mapped files, which means icreasing of performace of working with with big files. But... well, it is not so good, as could be. Generally speaking, it works, but has some serious pitfalls, which are well-known and described (and discussed) here: (fixed in 1.6)

In two words, you can't unmap file from memory, which is causing all other issues. It is released only when GC collects that buffer. Such limitation doesn't allow you to use that feature in any application which need to release file or work with mappings really intensive (create lots of new ones).

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, 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.