When do you throw an exception? I never asked myself that question until a few weeks ago when some guys on my team started wondering aloud. I suppose I never asked because I just threw exceptions whenever I felt like it. But the question on the minds of my colleagues has got me thinking too. When should I throw exceptions?
One team member says that exceptions should only be thrown when there is exceptional behavior. That sounds reasonable, right? But now, we have to define exceptional behavior. Google says that an exception is, “A person or thing that is excluded from a general statement or does not follow a rule.” So exceptional behavior is conduct that breaks rules, simply put.
Take the following code for example:
The purpose of the function is expressed in the function’s name: “Get a monkey by its ID.” So, what if there is no monkey found by the given ID? Is that exceptional behavior? If you were inclined to say, “no,” you could do a few things in response to your lack of monkey. You could return null, but that’s a cheap shortcut that will cause problematic code down the line. You could possibly change the method to return an object that contains a monkey, a success flag, and a message (for when there is no monkey found), like so:
So, then, your function can go something like this:
There is something wrong with that function that I REALLY don’t like. The MonkeyResponse class will ALWAYS return a null or some empty value. If there is a monkey found, it will return a null/empty message. If there is no monkey found, the monkey property will be null. Neither of those options are satisfactory.
The fact of the matter is, there is a rule being broken in this function when an invalid ID is passed in. The function’s purpose is to retrieve a monkey. If that is not possible, then the code’s course has to change drastically from it’s intended purpose. We need to call a spade a spade, address the broken rule appropriately, and throw an exception.
Here’s my refactored function including an exception:
I got rid of the MonkeyResponse object because I don’t need it anymore. Now, my function returns a Monkey if one is found, and throws an exception when someone passes in an invalid ID. This feels much better. I know that the repo is returning a null when no monkey can be found, but that’s a refactor for another day. I would probably move the exception from this function into the repo function and let the exception bubble up.
This really isn’t rocket science, but I think it’s important to question your methods from time to time. I’ve been throwing exceptions (on purpose) without justification for years. Now, I have at least gone through the thought process of justifying my methods. In a nutshell, here’s what I’ve come up with:
Throw an exception when a function’s behavior breaks the rules and causes the code to change course as a result.