6 Tips to Improve Your Exception Handling

Getting exception handling right can save you hours (or even days) of troubleshooting. Unexpected production issues can ruin your dinner and weekend plans. They can even affect your reputation if not resolved quickly. Having a clear policy on how to manage exceptions will save you time diagnosing, reproducing, and correcting issues. Here are 6 tips to improve your exception handling.

1. Use a single, system-wide exception class

Instead of creating separate classes for each exception type, create just one. And make it extend RuntimeException. This will reduce your class count and remove the need to declare exceptions you aren’t going to handle anyway.

I know what you’re thinking: How will I tell exceptions apart if they’re all the same type? And how will I track type-specific properties? Read on!

2. Use enums for error codes

Most of us were trained to put the cause of an exception into its message. This is fine when reviewing log files (ugh), but it does have drawbacks:

Putting info in the message also leaves the wording up to each developer, which can lead to different phrases for the same failure.

A better approach is to use enums to indicate the exception’s type. Create one enum for each category of errors (payments, authentication, etc.). Make the enums implement an ErrorCode interface and reference it as a field in the exception.

When throwing exceptions, simply pass in the appropriate enum.

Java

1

thrownewSystemException(PaymentCode.CREDIT_CARD_EXPIRED);

Now when you need to test for a specific case, just compare the exception’s code with the enum.

Java

1

2

3

4

5

}catch(SystemExceptione){

if(e.getErrorCode()==PaymentCode.CREDIT_CARD_EXPIRED){

...

}

}

User-friendly, internationalized text can now be retrieved by using the error code as the resource bundle’s lookup key.

3. Add error numbers to enums

In some cases a numerical error code can be associated with each exception. HTTP responses for example. For those cases, add a getNumber method to the ErrorCode interface and implement it in each enum.

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

publicenumPaymentCodeimplementsErrorCode{

SERVICE_TIMEOUT(101),

CREDIT_CARD_EXPIRED(102),

AMOUNT_TOO_HIGH(103),

INSUFFICIENT_FUNDS(104);

privatefinalintnumber;

privatePaymentCode(intnumber){

this.number=number;

}

@Override

publicintgetNumber(){

returnnumber;

}

}

Numbering can be globally unique across all enums or each enum can be responsible for numbering itself. You can even use the implicit ordinal() method or load numbers from a file or database.

4. Add dynamic fields to your exceptions

Good exception handling means also recording relevant data, not just the stack trace. Doing this will save you big time when trying to diagnose and reproduce errors. And customers won’t have to tell you what they were doing when your app stopped working (you’ll already know and hopefully have fixed it).

The easiest way to do this is to add a java.util.Map field to the exception. The new field’s job will be to hold all your exception related data by name. You’ll also need to add a generic setter method following the fluent interface pattern.

Throwing exceptions, with relevant data, will now look something like the following.

Java

1

2

3

4

thrownewSystemException(ValidationCode.VALUE_TOO_SHORT)

.set("field",field)

.set("value",value)

.set("min-length",MIN_LENGTH);

5. Prevent unnecessary nesting

Long, redundant stack traces help no one. Even worse, they waste your time and resources. When rethrowing exceptions, call a static wrap method instead of the exception’s constructor . The wrap method will be responsible for deciding when to nest exceptions and when to just return the original instance.

6. Use a central logger with a web dashboard

Consider this tip a bonus. Depending on your situation, getting access to production logs could be quite a hassle. A hassle that may involve multiple go-betweens (since many developers don’t have access to production environments).

Things get worse if you’re in a multi-server environment. Finding the right server — or determining that the problem only affects one server — can be quite a headache.

My recommendations are:

Aggregate your logs in a single place, preferably a database.

Make that database accessible from a web browser.

There are many ways to do this and may products to choose from: log collectors, remote loggers, JMX agents, system monitoring software, etc. You can even build it yourself. The main thing is that you do it soon. Once you have it, you’ll be able to:

Prevent testers from creating multiple tickets for the same bug. Plus they’ll have an exception URL to put in their ticket.

Save money for your business.

Keep your weekend and reputation intact.

What are your Tips?

I hope you find these tips useful. Many disasters and wasted hours have been averted by having the right info in my exceptions and having them in an easy to access location. If you have a few exception handling tips of your own, I’d like to hear them.

Excellent approach! I’ve been struggling with how to build a simple but usable REST exception handling process complete with logging to a mongodb for production use. I think this may just fit the bill nicely.

This is a good approach although I think one exception class might be a bit far, you could consider creating a base class and then sub exception classes with different Enums. This would allow you to have componentised development but still use the same base mechanism for handling errors.

Also a very minor point and I’m sure just used for an example but CREDIT_CARD_EXPIRED is not really an exception as this is an expected and predictable state for a credit card to be in and should be handled by the “Main Path” of your program.
This is my opinion, of course, but Exceptions should only be used for Exceptional circumstances (see a dictionary definition) otherwise you can end up throwing exceptions up several layers of your application because it is easy or using exception for logical flows.

Owen — you’re right that a single exception class is taking things far. Probably too far for most Java developers to stomach. For the skeptical, I say try to keep an open mind. I’ve had a surprising amount of success with the single exception approach over the years.

Having said that, I do like your recommendation. It’s a good middle ground. Most developers can accept it and it probably won’t break any of my production code 🙂 As long as you’re recommending a SystemException subclass per subsystem (accounts, inventory, tickets) and not the class-per-error we see today, then I’m on board.

Re: CREDIT_CARD_EXPIRED. IMO there’s a fine line between the main, alternate, and exceptional paths. (Is FileNotFoundException really an exceptional case???) I do agree with you that CREDIT_CARD_EXPIRED is questionable, like INVALID_USERNAME_OR_PASSWORD for example. A better example might have been something like UNSUPPORTED_CARD. Thanks for pointing this out.

My framework does something pretty much similar but the part that translate the messages needs to be an interface because does not know anything about specifics enums. So, I have an error service which is initialized in the framework by the app code where it ‘mount’ all error codes to be translated in the future.

Nice approach. I like your decoupling of user messages from exceptions/error codes. This also let’s you mount the appropriate messages for the current user role. Internal agents might see a different message than partners or customers for the same exception.

#1 and #4 together make refactoring more difficult than necessary. Subclasses with dedicated getters and setters provide comile-time safety instead.
For a meaningful I18N handling, there should be a method returning all fields as an object array. That would allow for using MessageFormat.
The luxury version would include a facility to translate properties before using them to the MessageFormat. E.g., the text associated with an HTTP error code has to be translated in the first step before being included in a localized error message in the second step.
Sub classes would make #3 simpler as well with generics being used to declare, which error code class will be returned from a particular sub class.

Interesting article. However, I don’t agree about TIP #1. Doing this makes it impossible to use the Java language catch clause to selectively catch or ignore errors (you have to call methods on the exception to select exceptions and possibly rethrow). A better idea is to make the single exception type a base class and subtype that. This would let you define subtypes like FatalException whose handling can easily be customized. With this approach you can still use the other tips. Remember: one of the strength of Java is that it is a typed language. Not using types in Java is almost always an error.

But I have one more question. Is there any way to output the log? You know we always need to support production but always can not have the permission to get the log directly. is it exist library to can to output log to web page with filter(like password hidden)? Thanks

I’ve read about a few log aggregators and cloud loggers, but haven’t personally used any. You can google “log servers” or “log management” to see a few.

My approach in the past has been to:
1. Filter out passwords in the SystemException.set method by excluding calls with the keys password, pwd, or passwd.
2. Log all exceptions to database.
3. Add a simple exception viewer to the website’s admin page.

I’ve got a background in languages that don’t have exceptions and am trying to learn.
I remain unconvinced that I should ignore the classes-as-types and use enums as types.
Aren’t subclasses easier to maintain?

I did same (with little variations) many years back and still using, so that we can automate error alerts. It gave many other benefits too.
we had following additions:
ErrorCategory (e.g. config, network, DB, Retryable)
ErrorSverity (e.g. fatal, error, warn) in error codes.
Overridden getMessage() for standard error message, which helped us parsing error logs.
Global exception handler which looked at error properties and acted accordingly.
Later this approach helped us in internationalisation too.
I like your dynamic fields in exception, hope I’m allowed to borrow it 🙂
Thanks for sharing.

I have been working on centralizing the Excepting Handling since legacy days. This article describes a perfect methodology, My experience thru 40 years of architecture (a model with technology agnostic building blocks of a solution) converges having a separate technical service (to be custom tailored to a specific system) as the process and workflow are pretty much similar in all the technical and business components of the architecture. In fact, we can workout for a standard that could be inter-operable among the systems across the enterprise. This article certainly is a start in this direction. I would recommend that we should work with OASIS to promote these concepts to standardize.

I’d have to say I partially disagree. Described tips are really good when dealing with service exceptions which have to be the response when something wrong happens in the back-end. These are gonna be the nice, detailed – and thus many in numbers – exceptions that will gently tell the customer what just happened. As said, this includes l10n and proper HTTP code handling, therefore a good pattern is to use enums and codes. BUT, when it comes down to exceptions in back-end applications that are not used as client API, a daemon for example, this whole article is of no use. Then you are the person who’s the target of the exceptions, via the logs and the exception handling composition. IMHO, business defined exceptions in combination with nested exceptions give quite more details, preserving the logs from stack-floods (in case one’s using containers like JBoss). In few lines you see exception propagation and causes with their meaningful messages so you can recreate the chain of events straight away in your mind. Just an opinion guys, have a productive day! 😉