6

Say you normally have FooException.

/**
 * @throw FooException If Foo is invalid for searching.
 */
public bool exists(Foo a)

But at some point you need to have two more specific exceptions for Foo.

/**
 * @throw FooSearchException (extends FooException) When "a" caused the error.
 * @throw FooReplacementException (extends FooException) When "b" caused the error.
 */
public int replace(Foo a, Foo b)

Because you want be able to know which of the two parameters caused the error.

At this point, what should I do with the exists() method? Should I change it to throw the most specific Exception type or should I keep it generalized as much as possible to uniquely identify a problem in a single routine? The exists() method doesn't need to differentiate between Search and Replacement parameters, but it is still about a Search. What should I do?

(Note that the change won't affect existing catch()es since both FooSearchException and FooReplacementException extend FooException)

1

1 Answer 1

5

Throw the most specific exception that already exists. It does no harm to the caller who doesn't care and will just catch the more general common superclass, but adds useful extra flexibility to a caller that distinguishes between them.

Be eager to change existing code from general → specific. It shouldn't break code, after all.

Be wary of changing existing code from specific → general, as that is more of a breaking change. If you realise another case should also be catered for though, then you've no choice: Never fake a general exception with a more specific case that does not apply.

Don't be inconsistent in your specificity though: Imagine a method that took an x and a y parameter and if x is out of a specific range throws an "argument out of range" exception, but if y is out of a specific range throws a general "argument" exception because catch it along with catching other issues with y. The result would just be confusing. (It is though fine to e.g. throw "argument out of range" if x or y are out of their respective ranges and "argument exception" if the combination of x and y is outside some collective range).

What I'm not covering here is the question of when to create another exception type to be more specific than what you have already got, which is a much more involved question. I will though say that I think it's worth considering them as "costing" something; if you're "spending" then what are you getting for your expense?

2
  • The one catch is not to throw LibrarySpecificException where the library being used is purely an implementation detail. That's going to be a problem if you ever stop using that library.
    – Doval
    Apr 1, 2015 at 19:11
  • @Doval though there are arguments for and against allowing LibrarySpecificException to pass through and then documenting the method as throwing FrameworksCommonException that it is derived from.
    – Jon Hanna
    Apr 1, 2015 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.