Re: A general approach to exceptions in Java

My previous post about exceptions in Java begs the question: Where do so called “business exceptions” fit in with all of this?

Business Exceptions are Checked Exceptions

Following on from my reasoning, the user is something that you have no control over. Therefore you expect these types of exceptions to occur. Making them checked exceptions forces you to handle them in some way.

A classic example of these errors are validation errors. These should be checked exceptions because usually you’d need to force the user to fix the entered data before the form can be submitted.

Dealing with Checked Exceptions

The problem of checked exceptions is: how do you handle them ? You’ve got to catch them somewhere (or rethrow), how do you know what to do with them ? This is usually a requirements question; this should be a hint to you to go back to the business and get some clarification on the requirements.

Advertisements

Persistent Strategies

I’ve just finished working on a cash management system. The core of what the system does is listen to messages produced by various sources and record a transaction (i.e. a debit and a credit) between two accounts.

For example, the system will listen to trade messages produced by our trading system and charge a trade fee to the client. This involves debiting the client and crediting the Fee house account.

This seems innocent enough, but to create a transaction you must have a reference to each of these accounts.

The client’s account is easy enough to find as all the required information is supplied in the trade message. But what about the house account ? How does the system find an instance of the house Account ?

One could do something like this, store the account number in a constant somewhere:

Account account = accountService.getAccount(FEE_HOUSE_ACCOUNT_NUMBER);

// create Transaction with client and house account

This is pretty bad IMO because there is duplication and “hard coding” ( even if it is in a properties file) of what house account numbers there are.

If you didn’t want to store the account number in code (or in a properties file which is almost as bad) you could add it to the static data for that transaction type:

@Entity
class TransactionType {
    String name;
    Account creditAccount; // this could be null to indicate that the account is based on the message
    Account debitAccount; // this could be null to indicate that the account is based on the message
    //...
}

then you would just find the TransactionType and the get the credit or debit account.

This would work, but it is very specific, since sometimes we may want to find the debit / credit account in a different way (e.g. “find the loan account associated with the client’s cash account”).

Enter the Persistent Strategy.

Basically, the idea is that rather than store links directly to Accounts in your static data, store a Strategy to obtain the right Account.

@Entity
public class TransactionType {</code>

    private String type;

    @ManyToOne
    private AccountAllocationStrategy toAccountStrategy;

    @ManyToOne
    private AccountAllocationStrategy fromAccountStrategy;
}

@Entity
@Inheritance
public abstract class AccountAllocationStrategy {
    public abstract Account getAccount(Transaction transaction);
}

What we’ve done is added a strategy for find the from / to account and we can have specific implementations:

@Entity
public class FixedAccountAllocation extends AccountAllocationStrategy {

    @ManyToOne
    private Account account;

    public Account getAccount(Transaction transaction) {
        return account;
    }
}

@Entity
public class InvestorAccountAllocation extends AccountAllocationStrategy {

    @Override
    public Account getAccount(Transaction transaction) {
        return transaction.getInvestorAccount();
    }
}

(there are a few more implementations I’ve left out for brevity).

You could achieve a similar effect by using a code of some sort (e.g. an enum) to denote the strategy and look up the strategy instance via Spring, but I like this better since it is more transparent and doesn’t require involving other frameworks. The major problem with the Spring approach is you’ve still got to specify the account numbers somewhere in your Spring context file which is duplication (once in the Spring file, once in the database) which, we all know, is bad :)

It might seem like abusing entities or the domain model but it is a really powerful pattern. Think of these entities as your rule domain. JPA makes mapping entities really easy and the number of strategies are finite so you can be quite creative in your mapping and inheritance hierarchies. You can also fully cache the strategy entities so performance will not be an issue.

We use this pattern in a few places in the system and it has made the code much cleaner and maintainable.

A general approach to exceptions in Java

Checked vs. Unchecked Exceptions in Java. The topic is pretty much as controversial as it comes. The debate over when to use a unchecked (those that are subclasses of java.lang.RuntimeException) vs. a checked (those that do not extend RuntimeException) is as old as Java itself.

I’ve witnessed many a debate over the topic over the years. When to use unchecked ? Are checked exceptions even a good thing ? Everyone has a different opinion on the subject so I’ll attempt to explain a general approach that hopefully will be helpful to decide when to use one type of exception over the other.

Both checked and unchecked exceptions are useful

Yes, both exception types are useful. You will sometimes find extremes of people who will only use one or the other, but by doing this you will not be able to benefit from the unique properties of each type: Unchecked exceptions don’t obviously have to be declared as part of the method signature, so the exception does not need to be handled or exposed in all the method signatures up the call stack. Checked exceptions are the opposite, they force the caller to either deal with the exception or inform its caller that it needs to deal with it and so on. These are both unique characteristics that are useful in different circumstances.

When to use each type

Exceptions are thrown because there is some sort of error that the system cannot deal with. An error can be categorised as either “there is an error in the code” or “there is an error with the system’s operating environment”. These two categories can can distilled into “an error that can be prevented”, vs. “an error that the system has no control over”.

So, if the system was perfectly designed, i.e. no bugs, then the first type of exception (an unchecked exception, an error in the code) should never occur. These are RuntimeExceptions, since there is no point bothering the caller of your object with errors that should not occur ! Examples of these are NullPointerException (check for null !), ArrayIndexOutOfBoundsException (check the length of the array !) etc.

The other type of exception, checked exceptions, are completely out of the control of the system and clients should be forced to deal with them. Examples of these are JDBCException (you can’t control whether the database will be available), FileNotFoundException (sure, you can check to see if a file exists, but you can’t guarantee it’ll be there when you read it) and RemoteException (you can’t ensure that the remote service will be available or bug free).

Perfect code vs. perfect environment

So, in summary I follow the following rules: use unchecked exceptions for errors that can be prevented and checked for those that cannot. It can also be thought of like this: If you have perfect code there should be no runtime exceptions. If you have a perfect environment there should be no checked exceptions. Obviously neither of these are possible, this is why we need both types of exceptions.