To Throw a Checked Exception or Not 6
I understand the concept behind “correctness” and the compulsion to throw checked exceptions by Java developers. It’s the only language that has a distinction between runtime exceptions and checked exceptions, and it has wreaked its havoc on the world. Consider the problem of finding a piece of data. For example, Location.find(String) would return a Location object that is related to the string that can be an ID, routing number, or name. The typical Java developer would then dutifully create a LocationNotFoundException and throw that any time find can’t return a result. That’s even more likely if the Location information is stored in a database. The alternative would be for Location to return null if it can’t find the object. So, let’s look at what might happen in some code:
// From an address object
Location getLocation()
{
Location location = null;
try
{
location = Location.find(routingNumber);
}
catch(LocationNotFoundException lnfe)
{
try
{
location = Location.find(addressName);
}
catch(LocationNotFoundException lnfe)
{}
}
return location;
}
There is so much extra crap in here that is required because of the fact the method throws an exception. All we want to do is try to find a location by a routing number, and then try looking up the location by name if the mapping hasn’t been made yet. Now, what if we didn’t have to worry about an exception?
// From an address object
Location getLocation()
{
Location location = Location.find(routingNumber);
if ( null == location )
{
location = Location.find(addressName);
}
return location;
}
Isn’t that so much cleaner? Sure, I could have let the method propogate the exception, but if the could assumes that no exception is thrown, it will never reach the second try. That’s why consistency, even if it is cumbersome, is important. There is a time and place for exceptions, but in many ways it would be more graceful to handle the error condition differently.
Now what about debugging? If a method returns null if it can’t find the result, what if the reason is because the database connection went down? Even if the thrown exception is the same, Java allows you to attach the exception that caused this one. The information is available. However, it is also my experience that many developers throw exceptions away. Did you see that in the first example? Logging helps, but in the long run, it is better to use unit tests to verify that everything behaves as expected.

A third approach uses a Null Object pattern and a special method.
Suppose the Location class has, in addition to each “find” method, a matching “orElseFind” method that simply returns “this”:
Now create a subclass of Location called NullLocation, which overrides each “orElseFind” method to call the related “find” method in the base class:
Now our client code can look like this:
You can chain as many “orElseFind” calls on as you’d like. If anything is found, the following orElseFind invocations just return what was already found. Until something is found, each orElseFind invocation executes the matching find call.
Maybe you’d want to add a simple “boolean isNull()” method to both classes to make it easier to test for a failure.
[Details: Of course, the “find” code in the Location class must return an instance of NullLocation in the event of failure. A singleton instance of NullLocation is appropriate. I’ve left the NullLocation class non-public as it probably would only be referenced by the Location class.]
A more elegant version of this is used in functional programming languages like Haskell and Scala. In those languages, a single “orElse” method that takes a functor or closure is all that’s needed. Alas, in Java the coding of the closure is currently about as painful as all of that try/catch stuff.
The clumsiness in the first example comes from the fact that you’re switching from using exceptions to null return values. It’s much cleaner if you stick with a single paradigm, like this:
Jukka Zitting, you are correct that sticking with the same paradigm is better in this little snippet of the code. However, in the context of where the snippet came from it’s not such a hot idea. It was found in the midst of some parsing code. The parser handled a message type that had two opportunities to get the correct location. Once was in the addressees, where this snippet was found, and later in the message where it lists the city it came from. It would be wrong to propagate the exception up to the parser level where the message would then be considered corrupt if it didn’t have the second shot at things. A more accurate example of what was happening was like this:
// From the message object void addAddress(Address address) { addresses.add(address); if ( "FROM".equals( address.getType() ) { Location location = address.getLocation(); if ( null == location ) { setOriginationName( address.getLocationName() ); } else { setOrigination( location ); } } }I can still see how that can be cleaned up further. Of course, from the puerile standpoint you shouldn’t use exceptions to perform alternate flows. From a performance standpoint, exceptions are much slower than if/else checks with nulls. However, if the Address object did throw an exception it would make the code a little more compact:
// From the message object void addAddress(Address address) { addresses.add(address); if ( "FROM".equals( address.getType() ) { try { setOrigination( address.getLocation() ); } catch(LocationNotFoundException lnfe) { setOriginationName( address.getLocationName() ); } } }Either way, it’s still not pretty.
Thanks for the context. I agree that the business logic in this case is better handled with normal control flow instead of exceptions. If it’s not exceptional for Location.find() not to find a matching location, then it shouldn’t throw exceptions in such cases. Of course, truly exceptional situations like database connection errors should IMHO still be handled with declared exceptions.
If you want to avoid null references and don’t want to go as far as Doug with dynamic orElseFind() lookups, you could use a special Location.UNKNOWN Null Object like this:
Exceptions can carry a lot of information about the error condition. If you can’t put any useful information in an exception, or if the caller just doesn’t get a real benefit from an exception, a null return value is good enough.
Methods named findXXX can always return null because that’s what find means: there’s the possibility that no results will be returned. Methods named getXXX ought to throw exceptions since there the intention to retrieve is much more significant.