Best practices for exception management in Java or C# [closed]

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:

  • Best Practices for Exception Handling | O'Reilly Media
  • Exception Handling Best Practices in .NET
  • Best Practices: Exception Management (Article now points to archive.org copy)
  • Exception-Handling Antipatterns

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

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.