Best practices for exception management in Java or C#

32,558

Solution 1

It seems odd to me that you want to catch exceptions and turn them into error codes. Why do you think the caller would prefer error codes over exceptions when the latter is the default in both Java and C#?

As for your questions:

  1. You should only catch exceptions that you can actually handle. Just catching exceptions is not the right thing to do in most cases. There are a few exceptions (e.g. logging and marshalling exceptions between threads) but even for those cases you should generally rethrow the exceptions.
  2. You should definitely not have a lot of try/catch statements in your code. Again, the idea is to only catch exceptions you can handle. You may include a topmost exception handler to turn any unhandled exceptions into something somewhat useful for the end user but otherwise you should not try to catch each and every exception in every possible place.

Solution 2

This depends on the application and the situation. If your building a library component, you should bubble up exceptions, although they should be wrapped to be contextual with your component. For example if your building an Xml Database and let's say you are using the file system to store your data, and you are using file system permissions to secure the data. You wouldn't want to bubble up a FileIOAccessDenied exception as that leaks your implementation. Instead you would wrap the exception and throw an AccessDenied error. This is especially true if you distribute the component to third parties.

As for if it's okay to swallow exceptions. That depends on your system. If your application can handle the failure cases and there is no benefit from notifying the user why it failed then go ahead, although I highly recommend that your log the failure. I've always found it frustating being called to help troubleshoot an issue and find they were swallowing the exception (or replacing it and throwing a new one instead without setting the inner exception).

In general I use the following rules:

  1. In my components & libraries I only catch an exception if I intend to handle it or do something based on it. Or if I want to provide additional contextual information in an exception.
  2. I use a general try catch at the application entry point, or the highest level possible. If an exception gets here I just log it and let it fail. Ideally exceptions should never get here.

I find the following code to be a smell:

try
{
    //do something
}
catch(Exception)
{
   throw;
}

Code like this serves no point and should not be included.

Solution 3

I would like to recommend another good source on the topic. It's an interview with inventors of C# and Java, Anders Hejlsberg and James Gosling respectively, on the topic of Java's Checked Exception.

Failure and Exceptions

There are also great resources at the bottom of the page.

I tend to agree with Anders Hejlsberg and you that the most callers only care if operation is successful or not.

Bill Venners: You mentioned scalability and versioning concerns with respect to checked exceptions. Could you clarify what you mean by those two issues?

Anders Hejlsberg: Let's start with versioning, because the issues are pretty easy to see there. Let's say I create a method foo that declares it throws exceptions A, B, and C. In version two of foo, I want to add a bunch of features, and now foo might throw exception D. It is a breaking change for me to add D to the throws clause of that method, because existing caller of that method will almost certainly not handle that exception.

Adding a new exception to a throws clause in a new version breaks client code. It's like adding a method to an interface. After you publish an interface, it is for all practical purposes immutable, because any implementation of it might have the methods that you want to add in the next version. So you've got to create a new interface instead. Similarly with exceptions, you would either have to create a whole new method called foo2 that throws more exceptions, or you would have to catch exception D in the new foo, and transform the D into an A, B, or C.

Bill Venners: But aren't you breaking their code in that case anyway, even in a language without checked exceptions? If the new version of foo is going to throw a new exception that clients should think about handling, isn't their code broken just by the fact that they didn't expect that exception when they wrote the code?

Anders Hejlsberg: No, because in a lot of cases, people don't care. They're not going to handle any of these exceptions. There's a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue. The programmers protect their code by writing try finally's everywhere, so they'll back out correctly if an exception occurs, but they're not actually interested in handling the exceptions.

The throws clause, at least the way it's implemented in Java, doesn't necessarily force you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, "throws Exception." That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody.

EDIT: Added more details on the converstaion

Solution 4

Checked exceptions are a controversial issue in general, and in Java in particular (later on I'll try to find some examples for those in favor and opposed to them).

As rules of thumb, exception handling should be something around these guidelines, in no particular order:

  • For the sake of maintainability, always log exceptions so that when you start seeing bugs, the log will assist in pointing you to the place your bug has likely started. Never leave printStackTrace() or the likes of it, chances are one of your users will get one of those stack traces eventually, and have exactly zero knowledge as to what to do with it.
  • Catch exceptions you can handle, and only those, and handle them, don't just throw them up the stack.
  • Always catch a specific exception class, and generally you should never catch type Exception, you are very likely to swallow otherwise important exceptions.
  • Never (ever) catch Errors!!, meaning: Never catch Throwables as Errors are subclasses of the latter. Errors are problems you will most likely never be able to handle (e.g. OutOfMemory, or other JVM issues)

Regarding your specific case, make sure that any client calling your method will receive the proper return value. If something fails, a boolean-returning method might return false, but make sure the places you call that method are able to handle that.

Solution 5

You should only catch the exceptions you can deal with. For example, if you're dealing with reading over a network and the connection times out and you get an exception you can try again. However if you're reading over a network and get a IndexOutOfBounds exception, you really can't handle that because you don't (well, in this case you wont) know what caused it. If you're going to return false or -1 or null, make sure it's for specific exceptions. I don't want a library I'm using returning a false on a network read when the exception thrown is the heap is out of memory.

Share:
32,558
AtariPete
Author by

AtariPete

Mobile Software Developer in the NYC area. Typically Blackberry, Android and iPhone development. I'm cofounder of Perk Mobile Inc. where we do mobile consulting and development. Also I organized the last MobileCampNYC3 event at Microsoft's NYC offices.

Updated on May 02, 2020

Comments

  • AtariPete
    AtariPete about 4 years

    I'm stuck deciding how to handle exceptions in my application.

    Much if my issues with exceptions comes from 1) accessing data via a remote service or 2) deserializing a JSON object. Unfortunately I can't guarantee success for either of these tasks (cut network connection, malformed JSON object that is out of my control).

    As a result, if I do encounter an exception I simply catch it within the function and return FALSE to the caller. My logic is that all the caller really cares about is if the task was successful, not why it is wasn't successful.

    Here's some sample code (in JAVA) of a typical method)

    public boolean doSomething(Object p_somthingToDoOn)
    {
        boolean result = false;
    
        try{
            // if dirty object then clean
            doactualStuffOnObject(p_jsonObject);
    
            //assume success (no exception thrown)
            result = true;
        }
        catch(Exception Ex)
        {
            //don't care about exceptions
            Ex.printStackTrace();
        }
        return result;
    }
    

    I think this approach is fine, but I'm really curious to know what the best practices are for managing exceptions (should I really bubble an exception all the way up a call stack?).

    In summary of key questions:

    1. Is it okay to just catch exceptions but not bubble them up or formally notifying the system (either via a log or a notification to the user)?
    2. What best practices are there for exceptions that don't result in everything requiring a try/catch block?

    Follow Up/Edit

    Thanks for all the feedback, found some excellent sources on exception management online:

    It seems that exception management is one of those things that vary based on context. But most importantly, one should be consistent in how they manage exceptions within a system.

    Additionally watch out for code-rot via excessive try/catches or not giving a exception its respect (an exception is warning the system, what else needs to be warned?).

    Also, this is a pretty choice comment from m3rLinEz.

    I tend to agree with Anders Hejlsberg and you that the most callers only care if operation is successful or not.

    From this comment it brings up some questions to think about when dealing with exceptions:

    • What is the point this exception being thrown?
    • How does it make sense to handle it?
    • Does the caller really care about the exception or do they just care if the call was successful?
    • Is forcing a caller to manage a potential exception graceful?
    • Are you being respectful to the idoms of the language?
      • Do you really need to return a success flag like boolean? Returning boolean (or an int) is more of a C mindset than a Java (in Java you would just handle the exception) one.
      • Follow the error management constructs associated with the language :) !
  • smaclell
    smaclell over 15 years
    @Josh, good point about swallowing exceptions but I believe there are few cases where it is acceptable to simply swallow exceptions. In the last project your code snippet was mandated, it reeked. Logging them all made it worst, My advice, if you cannot handle the exception try not to swallow it.
  • AtariPete
    AtariPete over 15 years
    i entirely agree. I only did Ex.printStackTrace(); as an example of something that I was doing in the catch (i.e. not rethrowing).
  • JoshBerke
    JoshBerke over 15 years
    Aggreed like I said this all depends on the app and specific context. There are times when I swallow exceptions although its rare, and I can't recall the last time I did;-) It was probally when I was writting my own logger, and the write to the log, and the secondary log failed.
  • AtariPete
    AtariPete over 15 years
    Thanks for this! I updated my question with info about your answer!
  • JoshBerke
    JoshBerke over 15 years
    I love the TryXXX pattern in .net.
  • Lordn__n
    Lordn__n over 15 years
    Checked exceptions aren't an issue in C# because it doesn't have them.
  • sina
    sina over 15 years
    Don't forget that the setup of an exception block costs too...
  • Rauhotz
    Rauhotz over 15 years
    The code serves a point: You can set a breakpoint at the "throw".
  • AtariPete
    AtariPete over 15 years
    this is a very valid comment, be respectful of the language and how it traditionally manages such issues. Don't bring a C mindset into a Java world.
  • JoshBerke
    JoshBerke over 15 years
    Weak point, you can tell VS to break at any thrown exception or you can narrow it down and choose a specific exception. In VS2008 there is a menu item under debug (You'll need to customize your toolbars to find it) Called Exceptions
  • Lena Schimmel
    Lena Schimmel over 15 years
    Imho, sometimes its good to catch errors: I rember a very memory intensive Java app I wrote. I catched the OutOfMemory-Ex, and showed a message to the user that he is out of memory, that he should quit other programs and told him how to start the jvm with more heap space assigned. I guess it helped.
  • Daniel Earwicker
    Daniel Earwicker over 14 years
    The "code smell" example has a definite side effect, even in that simple form. If // do something includes any try/finally blocks around the point that throws, the finally blocks will execute before the catch block. Without the try/catch, the exception will fly all the way up to the top of the stack without any finally blocks being executed. This allows the top-level handler to decide whether or not to execute the finally blocks.
  • neal aise
    neal aise almost 14 years
    Point 2. is a great idea indeed.
  • Hakanai
    Hakanai over 11 years
    As for why someone would want error codes instead of exceptions... I always thought it was weird that HTTP still uses error codes, even though my application is generating an exception. Why can't HTTP let me pass the exception through as-is?
  • supercat
    supercat about 11 years
    It sounds like Mr. Hejlsberg is justifying Pokemon exception handling. One of the huge problems with the design of exceptions in Java and C# is that way too much information is encoded in the type of an exception, while information should should be stored in exception instances isn't available in any consistent way. Exceptions should propagate up the call stack until all of the abnormal conditions represented thereby have been resolved; unfortunately, the type of an exception--even if recognized--does little to indicate whether a situation is resolved. If an exception is unrecognized...
  • supercat
    supercat about 11 years
    ...the situation is even worse. If code calls FetchData and it throws an exception of an unexpected type, it has no way of knowing whether that exception simply means that the data is unavailable (in which case the ability of code to get by without it would "resolve" it), or whether it means the CPU is on fire and the system should do a "safety shutdown" at first opportunity. It sounds like Mr. Hejlsberg is suggesting that code should assume the former; perhaps that's the best possible strategy given the existing exception hierarchies, but it seems icky nonetheless.
  • lindenrovio
    lindenrovio over 10 years
    the best you can do is to wrap your error codes in a monad
  • Didier A.
    Didier A. over 9 years
    @Trejkaz You don't want to return the exception detail to users, because that is a security risk. This is why HTML servers return error codes. It's also a localization issue to return an error message, and probably makes the HTML bigger in size and slower to return. All these are why I think HTML servers return error codes.
  • Didier A.
    Didier A. over 9 years
    I think it's better to say: "You should only supress exceptions that you can actually handle."
  • Didier A.
    Didier A. over 9 years
    I agree that throws Exceptin is ridiculous, because almost anything can throw an exception, you should just assume this can happen. But when you specify exceptions like throws A,B,C, it's just an annotation, to me, it should be used like a Comment block. It's like saying, hey client of my function, here's a tip, maybe you want to deal with A,B,C, cause these errors are likely to happen when using me. If you add D in the future, it's not a big deal if it's not being dealt with, but it's like adding new documentation, Oh by the way, now it would also be useful to catch D.
  • Hakanai
    Hakanai over 9 years
    @didibus Why do you think that security concerns should create an inconvenience in development? I never said anything about production. As for error message localisation, the entire web site already has that issue and people appear to be coping.
  • Didier A.
    Didier A. over 9 years
    @Trejkaz I'm not sure which Website you are talking about. I'm talking about HTTP error codes. These are standard, and they are returned by webservers as standard errors. If the webserver were to return more details of the error, it would potentially leak data about your site. So it only returns a standard error. You can look at the logs for the details. Similarly, the browser responds to the error, by displaying a relevant message to the user, such browser can map the error code to the appropriate local for the user's language. As for your own errors, you're free to implement whatever.
  • Didier A.
    Didier A. over 9 years
    @Trejkaz The protocol has native support of error handling. That's the point of the error status codes. The HTTP Response can include an error code and an error message so that the HTTP requester knows something went wrong and details about it. By default, HTTP Servers do not return lots of details in the error response because of security concerns and also user friendliness. Some browsers like IE will even replace the error response with it's own error to make it "friendlier" to users.
  • Didier A.
    Didier A. over 9 years
    @Trejkaz Most servers can be configured to return detailed errors instead, useful during development. Now keep in mind, this is the HTTP server's errors. If you use something else to generate your responses, like PHP, or ASP.NET or RAILS, etc. It will be up to them to add the details to the error response and pass this response to the server, or tell the server to send an error response with a given error message. Most of these can also be configured to do so.
  • Didier A.
    Didier A. over 9 years
    @Trejkaz Not sure what web server you use, or what back-end you use, but here's how to enable detailed errors in IIS7: iis.net/learn/troubleshoot/diagnosing-http-errors/…
  • user1451111
    user1451111 almost 6 years
    what do you mean by *handle* when you say "You should only catch exceptions that you can actually handle."