views:

305

answers:

9

Hello. 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:

  1. Does using try-catch() excessively have a negative impact on performance?
  2. 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?
  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?
  4. 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.

+1  A: 

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.

Justin Standard
That sounds like a great idea, thanks. However, i am not sure i should do this now .. or when the app is more mature. There are a LOT of things that needs to be done..and the time is passing fast :-(.
Hypercube
If you wait until the app is "more mature" it will be too late, probably, to implement a robust exception handling system. Plus, you will waste a lot of time having the gui layer handle low level exceptions that perhaps get thrown its way. This scheme saves you time in maintenance, AND in development.
Justin Standard
Yes, i guess you are right, and i've seen the effects of NOT doing something from the start. A few days ago, i've introduce log4J in my app and change the way icons are loaded. Man, that was painful..but..was few hours well spent. I will try to allocate time and resources to implementing the handling system.
Hypercube
+3  A: 

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:

  1. No, using excessive try/catch will not have a performance impact
  2. 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).
  3. 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.

Jeff

Jeff Storey
Yes, i am aware of Thread.setDefaultUncaughtExceptionHandler. I think it's ..magic! :-). But how could one implement that feature to be able to handle specific errors and maybe recover the GUI app from a nasty crash? I've declared the anonymous UncaughtExceptionHandler (see my initial question) , but i use it now just to log, display a message and exit the app..
Hypercube
As I'm sure you know, the uncaught exception handler is used to catch exceptions that weren't caught and handled elsewhere. At this point, if the uncaught handler gets it, it means no one else knew how to handle the exception and there isn't anything you can do about it. If you need to recover from it, the uncaught exception handler isn't the place to do it. The object that can do the recovering should catch it and handle it. Typically uncaught exception handlers do what you have done (they don't always exit, but they can).
Jeff Storey
Aw..i see..so, i was wright by using the uncaught exception handler just to log the problem, display the message that app will close and actually close the app?
Hypercube
yep, that's the typical usage.
Jeff Storey
+1  A: 
  1. 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.

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

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

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

Kaleb Brasee
OK, assume that i am not familiar with Spring (it's on my TODO though, now). What if MethodA encounter an exception and i use unchecked Exception to deal with that? Should i use a test if the generated exception is a checked or unchecked one? (Assuming that different actions are required) Like testing an ex with instanceof?
Hypercube
A: 
  • 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.

Pascal Thivent
Using specific exception types is better? - Here is what i wanted to say catch(Exception e){ //do something - 90% of cases log the details and return the default method value }OR catch(ArrayIndexOutOfBounds aob){ //log the aob exception return default method value } catch(SQLException e){ //log the exception details return default value }What if, using the 2nd scenario a NullPointerException occured and i didnt write any code for it? Using Exception would have caught the NullPointerException...
Hypercube
Hmm..i would have formatted that..but the magic buttons are not visible :-(
Hypercube
Oh, ok, I see now. I usually prefer to catch the most specific exceptions. But sometimes, I do catch a more generic one. Just don't `catch (Throwable t)`, especially if you don't know what you are doing. NPE are bugs, they shouldn't occur and should be fixed.
Pascal Thivent
Stupid question #1: what is NPE? :-)Stupid question #2: is it required to choose the most satisfactory answer? Honestly, all the answers helped me to understand the principles here and i am now SOMEWHERE, as the opposite of the initial place called UNKNOWN, when i asked my initial question.
Hypercube
There are no stupid questions, only stupid answers. Question #1: NPE stands for `NullPointerException`. Question #2: well, maybe you could wait a bit to see how the community value the answers by voting but **you** are the one with expectations and the final decision is up to you :)
Pascal Thivent
Yes, i got this answer from NawaMan that was absolutely fantastic. Concise, with attached code to make it easier to understand..that was great. I am also grateful to all the people who have answered..and if i may say so..this website is one of the best things i've seen online so far..and i've seen a lot :). Good work.
Hypercube
Once when I was in college a student said, "This is probably a stupid question, but ..." At which point the professor interrupted and said, "There are no stupid questions. It's just the people who ask them." :-)
Jay
I think that's the only thing that professor said that I still remember.
Jay
Oh my :-D. I wonder if that was funny :-)).
Hypercube
+1  A: 

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.

meriton
Return value vs. throwing an exception<p>I always log "events" like this in the log. The question with the returned value was..what value should i return? If method type returns object Dogs and error occurs, should i return null, or a new Dog()? This is important, as a general principle.
Hypercube
Specific exceptions : CASE1. Method1 throws E1, E2, E3. Method2 catches E1, E3. Somehow i think it's wrong that E2 is trowed, but not catched. CASE2. Method1 throws EXC. Method2 catches Ex1, Ex2, but EXC is of Ex3 type, therefore NOT catched by the caller.
Hypercube
Whatever value you return to indicate an error, the caller will probably have to check for it, so the returned value should be easily distinguishable from a return value indicating success. I'd therefore return null rather than a new Dog.
meriton
We make sure every exception is handled by having a catch (Exception) in every thread's run method. This is neccessary for those exceptions nobody anticipated, for instance a NullPointerException thrown due to a bug.With this handler in place, we feel it is ok to not catch exceptions in the business logic unless we can do anything more meaningful about them there.
meriton
Thanks, the code sample and the death of the new Dog() are easy for me to understand. It is a lot more clearer for me now on what should i use in the context of my question.
Hypercube
A: 

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.

Gzorg
I totally agree with that. Having 100 steps to perform, each one with at least 1 technical explanation of what went wrong doesn't sound like fun for the user..So, always log the details and throw it further..but throwing doesn't mean the app could not close, if the upper layer don't make any effort to deal with that..right?
Hypercube
The app should close only if it is the best option, which should not go without the app at least notifying the user that it knows it just crashed.It's the job of the highest layer (the app) to deal with exceptions. The lower layers only throw them, regroup them into fewer exceptions, or maybe log them.Be critic though, as I don't have too much experience yet, and maybe what I say is just not realistic... But the guys at se-radio know better than me :).
Gzorg
OK, i will try to criticize :-). I remember someone here i think saying once that he don't like all the exceptions leaking up to main..and i tend to agree with that. I think that at least some of the problems should be dealt with "on site".
Hypercube
+1  A: 

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!!)

NawaMan
EVRIKA! U got my vote, man :-). That was outstanding...thanks so much.
Hypercube
Just a couple of comments I want to make here. In the first example of catch the ArrayIndexOutOfBoundsException and doing nothing is not good practice. You'll never know if that exception occurs.Also, returning null can be dangerous from method that returns a collection/array. Now the caller needs to check if ( users == null). it would be better practice to return an empty array.
Jeff Storey
You are right about that Jeff. The example is just that an example.
NawaMan
Right, I just wanted to particularly point out the one about the exceptions since this posting is about exceptions.
Jeff Storey
I would say, regarding the "replacement code" above that using something like final int LENGTH = Users.length and for(int i = 0; i < LENGTH; i++) and AVOIDING the Exceptions is the best u can do here. One small variable and a computation of size() outperform the instantiation of and AOB. This can be tested.
Hypercube
Well, in regards to the LENGTH problem. The reason this can be interesting is that you do not need to check if i is beyond LENGTH or not. Java check that behind the scene anyway. If you are looping many many round. The cost of exception will worth the cost of checking. And as I say this is an example. You can use the same idea when the checking cost much more.
NawaMan
Also, most of the case, maintainability is more important than optimization so I do agree that this is not what many people will use.
NawaMan
+1  A: 

Many good answers, let me just add a couple of points that haven't been mentioned.

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

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

Jay
That was an awesome response. InputException will see the daylight ASAP. I will never use return values of error codes instead of exceptions. But..assume this : i try to extract some data from db and hold the data in some java collection. If everything is OK, but there are no results, should i return a new java collection or a null value? I know i can do both and have in mind what to do with it, but what is the best practice here?Thank u.
Hypercube
Without more details, my gut feel would be: If "no data" is a valid condition and can be readily handled in the main line of code, then I'd return null. If it's an error condition -- not necessarily "database crashed" but "there should be data and there isn't" -- then I'd make it an exception. Frankly, if the call and the function were within my own code, I'd base the decision on what I want to do when it happens. If it's a generic module that will be used by code I didn't write, than I'd base it on what sounds logical in context.
Jay
+1  A: 

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.

Thorbjørn Ravn Andersen
What is a NullObject? Assuming the scenarios : 1. I am using a database select, but there are no results. Suggested return : new Object of the method return type (vector, array, object, etc).2. I am using a database select but an error or an exception occured. Should i return a null value, a NullObject(of the method return type) or a new Object (of method return type)? Should i make or not the difference between :a) the select has results; b)the select was bad/incompatible with the database, hence, no results are there.?
Hypercube
For a database request an emtpy resultset would be an excellent suggestion if all you want to do with it is iterate over it.But, how would you differentiate between those conditions if you just return null in the first place?
Thorbjørn Ravn Andersen
I have documented myself about NullObjects..there is quite a fuss world-wide about them, and in some cases, they are useful, A bit more explicit term should have been "EmptyObject" or even "JokerObject" :-), as a NullObject is able to substitute any other objects of his kind. Thanks for introducing the term to me and to readers who were'nt aware of his existence.
Hypercube