Don't keep exceptions quiet

You can’t handle the truth!

We’ve realised that a few of our recent posts have been quite high level so we figured that we should get back to the down ‘n’ dirty of the coalface! This post is quite niche but certainly a topic that most developers have encountered at least once. Exceptions. Boring we hear you say! To us exceptions form one of the cornerstones of writing reliable code – not only do they allow us, as developers, the ability to handle circumstances that weren’t necessarily expected or anticipated, they also allow debugging of the why, when and what. Without the ability to cleanly handle exceptional circumstances and gracefully deal with them we would be somewhat flying blind and still enjoying the reams of information provided by, “Segmentation Fault”.

This post isn’t about how to use exceptions, per se, it’s more about when to use them. “Wait!”, “Hold up there cowboy!” we hear you scream, “We know how and especially when to use exceptions thank YOU very much! Hmmph!”. Well yes, we’re sure you do. The question we’ve been pondering lately is really when are exceptions appropriate vs when defensive coding is more appropriate – is that truly an exception set of circumstances or were you kinda expecting it to happen?

Consider the following code (We don’t claim that any of the code used in this code is of any quality at all, it’s merely to prove our point…):

public class AnimalLister {

	private class Animal {

		private String name;

		Animal(String name) {
			this.name = name;
		}

		public String getName() {
			return name;
		}
	}

	public AnimalLister() {}

	public static void main(String[] args) {
		new AnimalLister().list();
	}

	public void list() {

		Animal[] animals = new Animal[3];
		animals[0] = new Animal("Dog");
		animals[1] = new Animal("Cat");
		animals[2] = new Animal("Mouse");

		int n = 0;
		while(true) {
			System.out.println(animals[n].getName());
			n++;
		}
	}
}

This is a rather trite, forced piece of code to list the names of animals. Bleeding edge stuff. The interesting function here is list(). Clearly, it’s not going to work very well, ArrayIndexOutOfBoundsException you chant. So, how do we fix this? Maybe we rewrite the list() method to be this:

public void list() {

		Animal[] animals = new Animal[3];
		animals[0] = new Animal("Dog");
		animals[1] = new Animal("Cat");
		animals[2] = new Animal("Mouse");

		int n = 0;
		while(true) {
			try {
				System.out.println(animals[n].getName());
				n++;
			} catch (ArrayIndexOutOfBoundsException e) {}
		}
	}

Great, huh? Well, we’re pretty proud of it! This code certainly works but it’s definitely a borderline criminal offence, at the very least it’s exception abuse. Why? Well, because we knew, at some stage of the program’s execution, there would be no more data in our index array and there’s really nothing exceptional about that. We could more sensibly write the code as:

public void list() {

		Animal[] animals = new Animal[3];
		animals[0] = new Animal("Dog");
		animals[1] = new Animal("Cat");
		animals[2] = new Animal("Mouse");

		int n = 0;
		while(true) {
			if(n <= animals.length-1) {
				System.out.println(animals[n].getName());
				n++;
			} else {
				break;
			}
		}
	}

This is definitely better than the previous situation where we used exceptions to handle the end of the loop. However, it’s still a bit shonky isn’t it? So maybe, just maybe, we use something a lil’ like this instead:

public void list() {

		Animal[] animals = new Animal[3];
		animals[0] = new Animal("Dog");
		animals[1] = new Animal("Cat");
		animals[2] = new Animal("Mouse");

		for(Animal animal : animals) {
			System.out.println(animal.getName());
		}
	}

Well, what’s the point then? Obviously nobody would be silly enough to use an exception to terminate a loop or to write code that doesn’t expect the end of the loop to actually appear. Quite. Let’s extend our example a bit further then…

public void list() {

		List<Animal> animals = new ArrayList<>();
		animals.add(new Animal("Dog"));
		animals.add(new Animal("Cat"));
		animals.add(null);
		animals.add(new Animal("Mouse"));

		for(Animal animal : animals) {
			System.out.println(animal.getName());
		}
	}

This gives us a nice little NullPointerException. Granted it’s a bit silly to add a null value to a list that you’re about to process but what if you’re not adding the items to the list, what if you’re adding values that some other service is passing you? So, defensive coding or an exception handler?

We believe it really depends on the system design – you have to ask yourself, as system designers reasonably be able to expect an element in a list might be null? What if we we using a map? “It might be OK with values being null, in that case defensive coding is the way forward. It might be null this time but next time we execute this code it might not be.

Conversely, if nulls are a very bad thing and they should never, ever be present then it’s probably an exception handler you want – if a null value is encountered then stop what you’re doing and go fix this problem, stat!

If finding a null is that bad then maybe using a collection that doesn’t allow nulls should be a consideration in addition to exception handlers. By subclassing a Java list implementation we can ensure that nulls to our list:

public class NonNullList<E> extends ArrayList<E> {

	public NonNullList() {}

	@Override
	public boolean add(E e) {

		boolean success = false;

		if(e != null) {
			success = super.add(e);
		}

		return success;
	}
}

If we use this list instead of the bog standard Java ArrayList we can ensure that nulls cannot be added. There is a danger that the program will silently fail if one attempts to add a null to the list – this can be easily handled by logging an error message. The more astute amongst you may be asking, “Why bother with all this – the exception handler was fine and dandy?”. Well, consider what happens if we add the following line to the list() method:

System.out.println(animals.size());

Well, if we use our NonNullList() class this prints out 3, however if we use the standard ArrayList implementation it prints out 4. This has implications whether we care about nulls in our list or not. Assuming that we only want to process non-null elements in our list size() will return the wrong value from a processing perspective and most likely cause errors which are much harder to trace down the line.

The lesson, well it’s better to stop the problem than handle the consequences, especially because the consequences are likely to be manifested in a different way and much harder to track down.

We hope that this has been another exciting instalment!

~23Squared