Fail fast with a meaningful exception type
I puzzle over this “problem” every time I run into it. I hesitate to call it foolproof code, but I like code that fails as quickly as possible when something goes wrong and tells you what went wrong. I’m thinking of a mistake made by another programmer, possibly me, rather than a user error. In other words, my code rests on internal assumptions. The question is which exception type to use when one of those assumptions is violated.
Take a simple example. We have a class that represents a car, and one of its attributes is its color.
public class Car {
public enum Color {RED, GREEN, BLUE};
private final Color color;
public Color getColor() {
return this.color;
}
}Now suppose we have an API that works with this class. The API assumes that a car always has a color.
public boolean isWomanCar(Car car) {
if(car == null) {
throw new IllegalArgumentException("car must not be null");
}
return car.getColor().equals(RED);
}The code checks its input argument correctly, but it also assumes the color will never be null. For the sake of the example, let’s set aside the fact that we could rewrite it to be null-safe. I want to fail fast rather than hit a NullPointerException deep in the code, so I’ll change the code to make my assumption explicit.
public boolean isWomanCar(Car car) {
if(car == null) {
throw new IllegalArgumentException("car must not be null");
}
if(car.getColor() == null) {
throw new ??????
}
return car.getColor().equals(RED);
}I’ve captured the assumption, but I’m unsure which exception type fits. I’ve narrowed it down to IllegalArgumentException, AssertionError or a custom type such as AssumptionException. The argument against IllegalArgumentException is that I use it for assumptions about input arguments. On the other hand, I’m effectively checking an assumption about an assumption on the input. The argument against AssertionError is that it shouldn’t be used for anything to do with input. On the other hand, this use is close to what it was designed for. I don’t want AssumptionException because it introduces a type of my own whose meaning I understand, but a developer using the API might not.
The example above is simplified to make the point clear. You probably have plenty of code of your own that relies on assumptions. I’ll probably end up using IllegalArgumentException anyway. It strikes me as the lesser evil.
Related articles
Related CZ Podcast episodes
- #3 · Java 6 SE, Vývoj webových aplikací
Dagi and Filemon discuss Java 6 and web application frameworks. · Czech audio
- #1 · Vývojová prostředí v Javě
The first CZ Podcast episode looks at Java development environments. · Czech audio