posted 18 years ago
The way I look at exceptions is this...when you write a method, you should specify a contract for that method, with preconditions and post-conditions. The preconditions specify what the caller must ensure about the state of the system before calling that method. If the caller meets all your preconditions (checks that the state of the system satisfies those requirements), then your method promises to meet the post-conditions you specify.
For some exceptional circumstances, even though the caller has met your specified preconditions for a particular method, you still cannot meet the promised post-conditions. In that case, you throw an exception to indicate that something has gone wrong that is out of both your and the caller's control. Should it be a checked exception or an unchecked exception?
That depends on what has gone wrong. If the situation that raised the exception has the system in an invalid, but possibly recoverable, state, then it would make sense to throw an exception back to the caller indicating the problem and let the caller decide if they can perform the recovery. If the system is in an inconsistent state that is not recoverable for the caller (and the caller's caller, and that method's caller, etc), then you throw an unchecked exception.
Examples might help. You are writing a method that takes a URL argument and tries to download the specified image. Preconditions: (1) the URL must not be null, (2) it must reference an image, not a web page or something else. If the caller meets these preconditions, you specify post-conditions: (1) the return value will be a byte[] containing the image, (2) getLastImage() on this object will return the image retrieved by the last call to this method.
Ok, so a caller comes along with a URL, does a null check, knows it references a valid image, etc, all the preconditions are met. Normally, your method would be able to meet the post-conditions, but it just so happens there is a lot of network traffic and you are not able to reach the server containing the image. You throw a checked exception back to the caller because this is situation can reasonably be recovered from--the caller can choose to wait a few seconds and try again, and it will probably work. The caller may decide to get the referred image from a cache because they don't necessarily care if it's changed since the cache was last updated. Whatever.
Another caller comes along and passes you a non-null URL that refers to a valid image. Again, your method should be able to meet the specified post-conditions. However, one of the things that your method does for some reason or another is that it goes and gets two numbers from a database and divides them (say it's keeping track of traffic statistics or something like that--these stats are absolutely required and not optional, and should therefore be specified as post-conditions as well--in addition to getting the image). In this particular case, though, the denominator supplied by the database is zero, and when you try to divide it throws an unchecked exception. But this is proper, because there's obviously an unrecoverable situation--some other part of the app at some earlier time, unrelated to what's going on at the moment, put that invalid zero in the DB. That part of the app contains a bug that allowed this invalid data into the DB, and there's not a darn thing you or the caller can do about it. So, you throw an unchecked exception because there's no way to recover.
Well...a small correction. For a particular case, you might be able to devise a scenario where the caller could recover this situation and continue on. But that missed the point, really--the question is, *should* the caller continue on processing, leaving the system hobbled and in this invalid state? The answer is no--when there's a bug roaming around the system, which there is because that denominator fetched from the DB should never have been put there in the first place, it is not acceptable to simply continue on processing and let the system further degrade. So even if you can continue on, you wouldn't want to--the only rational thing to do here is recognize that the system is broken and go and fix the bug.
So, to sum up, checked exceptions represent problems that occur as a normal part of the processing in an application...they are exceptional conditions that arise to make continuing on impossible even if all your code is perfect and bug-free.
Unchecked exceptions represent a problem with your code--things have entered an inconsistent state and even if processing could continue, it shouldn't, because the bug needs to be ferretted out and fixed, and this will not ever happen if the system just buries the problem and continues bumbling forward until things degenerate to an irreparable state.
Just for the sake of completeness, I might as well address errors. These happen when some hard limitation of the system has been exceeded and processing cannot continue because of an irrecoverable problem (again, read this as "a situation you wouldn't *want* to recover from even if you could", instead of "a situation that could possibly be recovered") having to do with the environment in which your program is running. In other words, something went wrong that has absolutely nothing to do with the logic in your program, and completely orthogonal to the problem domain over which you're operating. For instance, you ran out of memory. Or the hard disk filled up. Or the CPU overheated. Or your little sister just poured a half a pint of Aunt Jemima buttermilk pancake mix all over your motherboard.
sev
[ April 16, 2004: Message edited by: sever oon ]