I was reading some things about exception handling in Java, to be able to write better code. OK, I admit, I am guilty; I\'ve used too much try-catch{} blocks, I\'ve used
Many good answers, let me just add a couple of points that haven't been mentioned.
For many, probably most, of the exceptions that I create, the only thing the program can realistically do is display an error message and give the user the opportunity to change his inputs and try again. Most validation errors -- invalid date format, non-digits in a numeric field, etc --fall into this category. For these I create a single exception type, which I usually call "BadInputException" or "ValidationException", and I use that same exception class throughout the system. When there's an error, I 'throw new BadInputException("Amount must contain only digits")' or some such, and then have the caller display it and let the user retry.
On the other hand, if the caller is reasonably likely to do different things in different cases, make them different exceptions.
Easy rule of thumb: If you have two or more exceptions that are ALWAYS handled with identical, duplicate code, combine them into a single exception. If your catch block is doing additional checking to figure out what kind of error this really is, it should have been two (or more) exception classes. I've seen code that does exception.getMessage and then looks for keywords in the message to figure out what the problem was. This is ugly. Make multiple exceptions and do it cleanly.
(a) It avoids the problem of "magic" return values, like non-null string is a real answer but null means there was an error. Or worse, "NF" means file not found, "NV" means invalid format, and anything else is the real answer. With exceptions, an exception is an exception and a return value is a return value.
(b) Exceptions neatly skip the main line of code. Usually when there's an error you want to skip a whole bunch of processing that does not make sense without valid data, and go right to displaying an error message and quitting, or retrying the operation, or whatever is appropriate. In the bad old dies we would write "GOTO panic-abort". GOTOs are dangerous for all the reasons that have been much discussed. Exceptions eliminate what was perhaps the last remaining good reason to use a GOTO.
(c) Perhaps a corrollary to (b), you can handle the problem at the appropriate level. Sometimes when an error happens you want to retry the exact same function -- like an I/O error might represent a transient communications glitch. At the other extreme, you could be ten levels deep in subroutines when you get an error that cannot be handled in any way but bombing out of the entire program and displaying a "sorry, armageddon has occurred, everybody in here is dead" message. With exceptions it's not only easy to choose the correct level, but you can make different choices in different modules.
Exception is there so the programmer of a Task does not have to deal with the problem by himself. (1): In case the problem is NOT LOGICAL to him to handle in the Task. A task to read a String from a stream should not handle disk error isn't it. But it should be very logical to handle if data does not contain a String.
(2): He can't handle it by himself (not enough info) A task to read a String from a file and file not found may ask user to select another file but how can the task now what folder the file might be what extension the file might be. Without knowing that, how can the task create a GUI to re-ask that.
(3): There is no logical (or manageable) way to distinguish between different return. If a task can't read the file and return null. What about if the file in the wrong format, return null too? How can these two differ? Exceptions can be used to differ that. That why it is called an Exception :-D.
(4): There are many similar tasks that need similar handling and writing that in all tasks is hard to maintain. Writing the handle code for all access can be a mess as you may require many duplications.
interface DBAccess {
public Result accessDB();
}
class DBOperation {
static public void DoOperation(DBAccess pAccess) {
try { return DBAccess.accessDB(); }
catch(InvalidDBPasswordException IPE) {
// Do anything about invalid password
}
catch(DBConnectionLostException DBCLE) {
// Do anything about database connection lost
}
// Catch all possible DB problem
}
}
...
private User[] ShowUserList_and_ReturnUsers() {
// Find the used.
// Show user list
if (Users.count() == 0)
return null;
else return Users;
// No need to handle DB connection problem here
}
private User[] GetUserProfile() {
// Find the used and return
// No need to handle DB connection problem here
}
...
/** An onClick event to show user list */ {
DBOperation.DoOperation(new DBAccess() {
public Result accessDB() {
return ShowUserList_and_ReturnUsers();
}
});
}
/** An onClick event to show a user profile */ {
DBOperation.DoOperation(new DBAccess() {
public Result accessDB() {
return GetUserProfile();
}
});
}
... Many more DB access
(5): Writing all the checking for error complicate or slow down the task. The above problem should show how can it help reduce the complication. Here is how it help not to slow down.
for(int i = 0; i < Users.length; i++) {
User aUser = Users[i];
// Do something with user
}
Replaced with
try {
for(int i = 0; ; i++) {
User aUser = Users[i];
// Do something with user
}
}
catch(ArrayOutOfBoundException AOBE) {}
The replacement code will be better performance if the number of user is large.
When a database error occurs, should one return a null value, and error code or throw the exception? Ans: Depending on what kind of error. Like if you can't find a user, that is not an error. But if the password is wrong or the connection is down, these are errors as trying to handle it in a normal way complicate the program.
(1). Using excessive try-catch() has a negative impact on performance? Ans: According to "Effective Java", it has very very tiny effect (only not good in loop) as far as I remember (I don't have the book with me here now).
(2). Using specific exception types is better? Ans: User specific one is better to avoid solving the wrong problem.
What if i missed to catch one of the possible X types of exceptions that could occur? Frankly, I've heard and use a mere 10% i think of the Java standard exceptions, in 2-3 years. Ans: Just like if you handle the error without exception, You can miss it too. You simply add it in when you find that out.
Yes, someone said that if the caller don't know how to deal with the trowed exceptions, he SHOULD NOT HAVE THE RIGHT to call the throwing method. Is that right? Ans: No, if I don't know what to do with some exception, re-throw it.
(3). I've read this article of Anders Hejlsberg, saying that checked exceptions are bad. Should that indicate that convenient exception swallowing is advised in some cases? Ans: I think he is talking about "Checking exception" as a feature for the compiler to ensure that some exception should be handle. The the idea of having exception.
(4). A picture is worth 1000 words..i guess some examples will help a lot here. Ans: The code above.
I got the run now .... Sorry ... :-p (Be there in a minute, honey!!)
Please, do not return null in case of non-fatal errors. Return a NullObject instead.
Otherwise you need a null check after each and every call to your code which is a pain, and if forgotten will cause the code to crash.