General problem
When writing a service method, there are advantages and disadvantages to throwing many exceptions versus abstracting them into a generic ServiceException. If you throw many exceptions, then you tell the client what exactly went wrong, so that the client can deal with the error more sensibly. If you abstract them into one ServiceException (e.g. via exception wrapping), then you are hiding the details of what went wrong, which can be useful in some scenarios but harmful in others.
For example, it can be useful to hide the details of went wrong in a DAO class, by throwing a generic DaoException. This way clients don't have to know whether you are reading from a file, a web service, or a relational database. But let's say you are validating user input, and there are at least four things that can go wrong with the user input. Isn't it more sensible in the latter case to throw four different exceptions, one for each thing that went wrong with the validation?
My specific problem
In my current project, I am working on a service method that saves a tree-like structure into a relational database. It has to validate the tree, and there are at least four things that can be wrong with the tree. There can be a duplicate node, or a node can be missing its mandatory X, Y, Z fields. Thus it makes sense for the service method to throw four different exceptions: DuplicateNodeException, MissingXException, MissingYException, MissingZException.
But the service method also uses the DAO class, which throws a DataAccessException via JdbcTemplate. I would like to know how to handle this DataAccessException. Would it make sense to wrap it as a ManagerException and then again as a ServiceException, and handle it as a ServiceException? Then I would be mixing both approaches of (a) throwing specific, descriptive exceptions and (b) throwing generic wrapper exceptions. Is a good idea to mix these approaches here?
The reason I ask is because it seems a little odd to me to catch these four validation-related exceptions and then in addition to catch a generic, nondescript ServiceException. It seems odd because the ServiceException is so abstracted that there's no way to tell at first glance what went wrong, you would have to check the log and read the exception message, or navigate the call hierarchy in the code. I'm asking, then, to verify that it's indeed a good practice, or common, or sensible, to mix these two approaches, because intuitively it seems strange to me. Are there any parallels in core Java where both approaches to exception handling are used in the same method?
Possible solution (per Andreas's answer)
Would it make sense to handle exceptions like this in my Service class? Below is some pseudocode presenting a possible solution. This way I'm not creating a useless, checked, nondescript ServiceException, but I do have a catch-all for unchecked exceptions (by catching Exception at the end). What are your thoughts on this solution?
class HttpService {
private Service service;
// ...
public HttpServiceResponse saveTree(Node root) {
try {
service.saveTree(root);
} catch (DuplicateNodeException e) {
return HttpServiceResponse.failure(DUPLICATE_NODE_EXCEPTION);
} catch (MissingXException e) {
return HttpServiceResponse.failure(MISSING_X_EXCEPTION);
} catch (MissingYException e) {
return HttpServiceResponse.failure(MISSING_Y_EXCEPTION);
} catch (MissingZException e) {
return HttpServiceResponse.failure(MISSING_Z_EXCEPTION);
} catch (Exception e) {
return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
}
}
}
Most exceptions should be unchecked, because they are not really actionable, i.e. there is really nothing the caller can do about it, other than passing it along, or logging it and failing whatever operation is currently in progress. Only exceptions that are actionable and requires such caller action should be checked, which is pretty rare.
If all the exceptions are unchecked, it means that the caller can do with a single catch-all. Since the service layer no longer needs to wrapper exceptions from e.g. the DAO layer, the caller can catch and handle specific exceptions, if desired.
I'm developing a library for Android, which I intend to open source and naturally I want to tick all of the boxes before I publish it - so users are suitably impressed with my code. Ahem.
As with many libraries, there are certain basic configurations necessary in order for the library to function.
public static final String API_KEY = "your_api_key_here";
In the above instance, when a user passes their API key to the library, I'm putting a simple string match in for "your_api_key_here" and if it matches, I'm going to throw a RuntimeException, as they quite simply haven't read the basic instructions and I want their app to die.
Is this a valid use of a RuntimeException? If it isn't, then in Java what is?
EDIT - My motivation for posting this is due to this post, where the OP is lynched by shouts of "why!?" for asking how to throw one.
ANSWER - In this instance, it seems to be more a matter of preference than right or wrong either way - at least no one has so far objected. This scenario should only occur during the testing phase for a developer and never in production. If this wasn't the case, I wouldn't have chosen an uncaught exception.
I've marked an answer as correct due to the most upvotes and following #mech's comment below, I have created a custom ReadTheDocumentationException which provides a suitably persuasive message.
I think you should use illegal argument exception which is subclass of java.lang.RuntimeException . You can do something like this
if(API_KEY.equals("your_api_key_here"))
throw new IllegalArgumentException("you message here");
For more info see this
You should create your own exception by extending RuntimeException or any other Exception. IllegalStateException would work for a case when someone terribly misbehave.
It sounds like part of your question deals with what is the proper use of RuntimeException, and partly deals with how your library should behave if misconfigured. I'll deal with mostly the former.
In Java, there are two types of exceptions, checked and unchecked.
RuntimeException and all of its subclasses are "unchecked" exceptions, meaning there is no requirement from the compiler to catch them. You can use these to crash your process if something is very wrong. The caller can still catch and handle them on their own, so be prepared that the caller may continue to call into your lib incorrectly.
Exception and all of its subclasses (except RuntimeException) are "checked", meaning that the compiler requires the caller to catch them or declare in a method declaration that it could be thrown. You use this in cases where you expect the caller to try to recover from whatever condition caused the exception to be thrown.
In your case, you can throw a RuntimeException with a meaningful message, or a custom subclass of RuntimeException with a message to indicate to the caller exactly what went wrong and how to remedy it. It doesn't really matter what you choose, but many people choose to subclass for clarity. I'd just make sure that the exception is never thrown by surprise in order to have clear rules for engagement for your lib.
I am developing an JAR library for database access. I first caught all the exceptions that are found in try blocks and handled them.
But later, I thought it would be better since its a library to throw the exception to the end-programmer to catch it and do the handling.
What is the best practice regarding handling exceptions in JAR files?
The following is a sample code from my JAR, and as you can see there are many exceptions thrown. Is that a good practice or is there a way to do this better? (Like defining a new custom exception; if so, how is it done?)
Any help regarding this is much appreciated.
public static NConnection getNConnection(String path) throws IOException, ParserConfigurationException, SAXException {
NConfigurations conf = new NConfigurations();
conf.setConfigurationLoc(path);
String dbPath = conf.getDatabasePath();
return createConnection(dbPath);
}
There is no easy answer to that and the community is somehow undecided about what is actually best practice. In a nutshell you can use checked exceptions if you want to force the caller to handle the case that something went wrong / give him a chance to recover from this exceptional state. Use runtime exceptions for any other cases like programming errors like violating contracts or such.
In my opinion it is best practice for any library to extend its own exception class, even if it does nothing more than wrapping the original exception. This way - as a client - I can read the stacktrace and easily spot in which part of my code something went wrong. E.g. if there is a DBFrameworkException it's much more clear than the common NullPointerException.
Also see Bloch's Effective Java item 58 for some good explanation on this topic.
In my opinion, you should catch all underlying exceptions such as the ones you have in the method signature (e.g. IOException) and then if needed you throw your own custom exception with the message and type you feel is appropriate.
The reason for this has to do with good programming practices where you may want to substitute a library you were previously using (e.g. a jdbc driver) with something else. you dont want user code to break when importing your new version on a lets say MySQL duplicate key error when instead you could be using a generic duplicate key exception.
I think throwing is a better way, because one who using the jar can handle those exceptions in java classes.Just like DriverManage.getConnection() throws ClassNotFoundException.
You can do it both ways: you can throw the original exceptions or you can nest them in your own custom exception. It is a design decision.
Usually it makes sense to throw exceptions that are related logically to the code functionality. For ex. if you do I/O operations, you would expect an IOException since this is a natural problem that may arise from the i/o operation.
In your case: it depends what is the NConnection abstraction all about. Maybe it doesn't make sense to expose the IOException if that's implementation specific. You can create your own application-specific exception and wrap the io exception:
try {
// code that throws i/o exception
} catch (IOException ioe) {
throw new NException("Something went wrong", ioe);
}
A quite theoretical question this time. So I'm using this function in Eclipse:
CsvReader csv = new CsvReader("src/maindroite.csv");
Which can't run because "Unhandled exception type FileNotFoundException". Ok, I understand that I have to add something for the case where the file doesn't exist, at which point I usually add a few lines to catche the exception and throw it away. But my question is: why do I need to catch the exception even when the file do exist? And actually, why do I even have this Exception thing for some functions and not others?
For example, let's say I'm trying to run:
ImageIcon icon1 = new ImageIcon("src/square.jpg");
ImageIcon icon2 = new ImageIcon("src/circle.jpg");
Where "square.jpg" exists but not "circle.jpg". The program will create icon1, but not icon2, because it can't. But I don't need to add an ExceptionHandler for the case where the image doesn't exist. What is the difference between both functions?
To sum it up:
Why do I have to add an ExceptionHandler when the file do exist?
Why do I have to add an ExceptionHandler for some functions and not others?
Thanks!
Why do I have to add an ExceptionHandler when the file do exist?
Basically you have to add it regardless, because you cannot write conditional code like that, in short there is no way that for the compiler to know before runtime if the file exists or not, therefore the compiler forces yo to put a try/catch block, since FileNotFoundException is a checked exception.
Why do I have to add an ExceptionHandler for some functions and not others?
You only have to add try/catch blocks to anything that throws a checked exception, that is anything that does **NOT* inherit from RuntimeException or Error classes. Subclasses of Error and RuntimeException are not checked exceptions and you may either put the try/catch or not the compiler does not care. Since the constructor for ImageIcon does not throw any kind of exceptions and will simply return null if the image does not exist there is no need to do a try/catch block.*
Even if the file exists now, on your system, it might not exist later. Or you may give this code to someone who doesn't have src/square.jpg. Or maybe there will be a hardware malfunction where something on your hard drive gets corrupted and accidentally deletes src/square.jpg. Maybe the user might even just delete the files.
Exception handling in Java forces you to think about what would happen in the worst case if something really bad happens (like src/square.jpg goes missing). Do you crash? Is it okay to continue on like nothing happened? You get to decide how to handle these failure modes in the catch clause.
Some functions don't require you to handle exceptions because there isn't really anything that could go wrong in the functions that you could be reasonably expected to handle.
1) Why do I have to add an ExceptionHandler when the file do[es] exist?
Because the Java compiler cannot know whether or not that file will actually exist at some arbitrary runtime. (Suppose the file was deleted after you compiled but before you ran the program?) Basically, your code must always have the logic required to handle conditions which aren't expected to happen but might anyway.
2) Why do I have to add an ExceptionHandler for some functions and not others?
There could be various reasons but here's the one you're probably seeing. Exceptions are thrown per method but caught per try/catch block or per method if they are propagated upwards. In your example, you could wrap each call to the ImageIcon constructor in its own try/catch block or both together, depending on what you want to do:
try {
icon1 = new ImageIcon("f1.jpg");
} catch (Exception e) { /* Handle the case for missing "f1.jpg". */ }
try {
icon2 = new ImageIcon("f2.jpg");
} catch (Exception e) { /* Handle the case for missing "f2.jpg". */ }
Compared to:
try {
icon1 = new ImageIcon("f1.jpg");
icon2 = new ImageIcon("f2.jpg");
} catch (Exception e) { /* Handle the case for missing "f1" or "f2". */ }
Because Java differentiates between what are known as "checked" and "unchecked" exceptions. It's the source of a lot of heated controversy, as to whether or not unchecked exceptions should even exist, and whether or not API methods should throw exceptions.
According to the Java Trails:
Here's the bottom line guideline: If a client can reasonably be
expected to recover from an exception, make it a checked exception. If
a client cannot do anything to recover from the exception, make it an
unchecked exception.
That's the so-called rationale.
Read more about "the controversy" here.
Why do I have to add an ExceptionHandler when the file do exist?
It exists for now, but there is no guarantee it will there every time. Could happen because of whole lot of reasons. If there is no file, it doesn't make sense to do InputStream and associated business logic and it is sure that your business won't be successful.
Why do I have to add an ExceptionHandler for some functions and not others?
Some Classes like Imageicon, they are not show stoppers for your business processing. If they are not there, that's Ok, you can still continue with your core business logic.
I feel this is main reason why some class mandate exceptions and some are not.
The idea behind checked exceptions is that they make it possible for the caller of a function to know what exceptions might escape from it. You don't have to actually catch the FileNotFoundException if you don't want to, provided you add throws FileNotFoundException to your method signature to let your caller know that such an exception might escape from your method.
The concept is a good one, but unfortunately there's no concise way to state that you want to catch all exceptions that aren't overly severe and wrap them into a common exception type for your caller. In a lot of cases, when an exception occurs, the real message you want to convey is either "the method didn't complete, but the system doesn't seem to be on fire and any side-effects have been undone", or "the method didn't complete, and the system doesn't seem to be on fire, but there may have been other side-effects." It would be helpful if there were a concise syntax to indicate regions of code where exceptions should be caught and wrapped to one of the above formats, but alas there is not.
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 ex.printStackTrace() in the catch, not even using a proper logger (actually the System.out and System.err were redirected to a PrintWriter, so a log was generated). However, after a few hours of readings, I find myself in a strange place: the unknown. If the exceptions are designed to pass info about abnormal states of flow, how does one know WHERE is the proper level to do something with that info?
For instance, when a database error occurs, should one return a null value or an error code, or throw the exception? If thrown, WHERE should that exception be handled? I understand that is no use even to log an exception if you cant do anything about it. However, in GUI apps, that could easily kill your GUI (I am using SWT and I've seen this too often), even for the case of the menuShown() method (an ArrayIndexOutOfBounds exception will close the app, if not handled). The example could go on forever, but here's the summary of questions:
Does using try-catch() excessively have a negative impact on performance?
Is it better to use specific exception types? What if I missed catching one
of the possible X types of exceptions that could occur?
Frankly, I've heard of and use a mere 10% I think of the Java standard exceptions, in 2-3 years. Yes, someone said that if the caller don't know how to deal with the thrown exceptions, he SHOULD NOT HAVE THE RIGHT to call the throwing method. Is that right?
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?
A picture is worth 1000 words; I guess some examples will help a lot
here.
I know the subject is eternal, but actually I am looking forward to review a middle-size project of 150 classes, using your advice. Many thanks.
The general rule of thumb for exception is, if you can do something about it, catch it and handle it, if you can't, re-throw it to the next method. To get into some of your specifics:
No, using excessive try/catch will not have a performance impact
Using the most specific type of exception you can. For example, you shouldn't generally throw Exception if you can avoid it. By throwing a specific type, you are letting the user know what can go wrong. However, you can rethrow it as something more generic so callers that are not concerned with the specific exception don't need to know about it (for example, a GUI won't care if it's an IOException vs an ArrayIndexOutOFBoundsException).
You will find people that like checked exceptions more and you will find people that like unchecked more. In general, I try to use unchecked exceptions because there is generally not a lot you can do about most checked exceptions, and you can still handle unchecked exceptions, you just don't have to. I frequently find myself rethrowing checked exceptions since I can't do much about them (another strategy is to catch a checked exception and rethrow it as an unchecked so classes higher in the chain don't need to catch it if they don't want).
I generally like to log exceptions at the point of where they are caught - even if I can't do anything about it, it helps to diagnose the problem. If you are not familiar with it, also look into the method Thread.setDefaultUncaughtExceptionHandler. This allows you to handle exceptions that are not caught by anyone and do something with it. This is particularly useful with a GUI app since the exception might otherwise not be seen.
To get into some examples:
try {
// some database operation
}
catch (IOException ex) {
// retry the database operation. then if an IO exception occurs rethrow it. this shows an example doing something other than just catch, logging and/or rethrowing.
}
I'll be happy to expand on any parts of this if you'd like.
Many good answers, let me just add a couple of points that haven't been mentioned.
Your exception types should be as specific as a caller is likely to distinguish them. By that I mean, if there are two possible errors, A and B, and any caller is likely to do exactly the same thing in both cases, then make a single exception class. If a caller is likely to do two different things, then make two exception classes.
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.
There are three good reasons to use exceptions rather than other ways of handling errors.
(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!!)
One thing that we have done on our team is to have custom exceptions for our errors. We are using the Hibernate Validator framework, but you can do this with any framework, or stock exceptions.
For example, we have a ValidationException to handle validation errors. We have a ApplicationException to handle system errors.
You DO want to minimize your try-catch-ing. In our case, we will have the validator collect ALL the validations in "InvalidValue" objects, and then throw a single ValidationException with the invalid value information bundled into it. Then you can report to the user which fields were in error, etc.
In the case you mentioned of a database error - you may not want to send the stacktrace to the UI (logging it is a good idea). This is a case where you can catch the database exception, then throw your own ApplicationException to your GUI. Your GUI won't have to know how to deal with an infinite number of server errors, but can be set to deal with the more generalized ApplicationException - possibly reporting that there is a problem with the server, and indicating that the user should contact your customer support department to report the problem.
Lastly, sometimes you can't help but use a lot of try/catch blocks because of the external APIs you rely on. This is fine. As mentioned before, catch the external exception, and format it into one which makes more sense to YOUR application. Then throw the custom exception.
While I don't have any numbers, I don't believe that try-catch has any significant impact on performance (not that I have seen). I think that if you don't run into many exceptions, the performance impact will be basically nothing. But in any case, it's best to care about implementing code correctly first and achieving good performance second -- a lot easier to do the second once the first is done.
I think the exception class should be specific as to what the exception really is. The problem I have with Java's SQLExceptions is that they give you no information about what really went wrong. Spring uses far a set of more descriptive database exceptions (deadlock exceptions, data integrity exceptions, etc.) That way you can tell what the problem really was.
Checked exceptions can be annoying, but I don't think they're always bad. For example, Spring uses unchecked exceptions for database errors, but I still check for them and either 1) handle them right there, if possible, or 2) wrap in a more general exception that the shows that the component failed.
Unfortunately, I can't think of any good specific exceptions. However, like I said, I've found Spring's exception rules to be helpful and yet not annoying, so maybe you could look at some Spring docs. The Spring database classes are a good example.
Using excessive try-catch() has a negative impact on performance?
This sounds like micro optimization and, if this really has a performance impact, you'll have to deal with a lot of bigger performance problems before to face this one.
Using specific exception types is better? 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. 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?
I'm not sure I understood the question but I'd say: "If you don't know what to do with an exception, re-throw it".
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?
Hell no. This just means that unchecked exception should be preferred in some cases especially when the user won't know what to do with a checked exception (e.g. SQL exception), or if there is not possible recovery,...
A picture is worth 1000 words..i guess some examples will help a lot here.
Spring's DataAccessException is a very good example. Check chapter 10. DAO support.
se-radio made a podcast episode about that topic of error handling that explains some philosophy about how to use exceptions, which can be restated as "Where to absorb them".
The main thing I retained is that most functions should let them bubble up, and most exceptions details should end up in a log file. Then the functions pass only global messages saying that something happened.
In a sense, this leads to a sort of exception hierarchy : one for each layer of code.
As I think they said, it doesn't make sense to explain to the user that such DB cluster failed because the DNS was unavailable, or because the disk was full. At that level, something happend that couldn't allow the transaction to complete, that's all the user has to know.
Of course, the developpers/administrators will be happy to see more details, that's why at the DB layer, the specific exceptions should be logged.
Return value vs. throwing an exception
The fundamental difference between an exception and a return value is that the return value is delivered to your immediate caller, whereas an exception is delivered to a catch clause anywhere in the call stack. This allows to reuse the same exception handler for many different kinds of exceptions. I recommend that you favor exceptions over return codes if and only if you need that feature.
Performance impact.
Every instruction has a negative effect on performance, including those in catch-blocks. However, any modern CPU can throw and handle millions of exceptions per second, so unless you throw thousands of them you won't notice a thing.
Specific exceptions
For throwing, be specific to allow specific handling.
For handling, you can be generic, but you should be aware that arbitrary exceptions can be delivered to your handler, including unchecked ones not declared by your callees.
checked
The debate rages whether methods should use checked or unchecked exceptions.
Never just swallow an exception. Handle or rethrow it. It simplifies maintenance if you don't discard evidence about failures.
Example
An application I worked on recently receives commands over the network which it then executes. This usually involves further interaction with remote systems, which might fail for a host of reasons. The methods to carry out the command don't catch any exceptions, letting them bubble of the call stack to the central exception handler in the command listener, which does the following:
for (int retries = 0;; retries++) {
try {
commandService.execute(command);
return;
} catch (Exception e}
Log.error(e);
if (retries < 3) {
continue;
} else {
saveForAnalysis(command, e);
alertOperator();
return;
}
}
}
We intentionally did not catch & rethrow exceptions in the processing logic, as we felt this would have added no value.
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.