Throwing a generic exception like FooServiceException
makes your method signature easy to read, but you're also assuming the caller is not likely going to want to differentiate. If he did, he could still do so, but he'd have to pilfer through your code to find out which specific implementations of FooServiceException
are thrown. Don't make the caller do that! That is why we can't have nice things!
On the other hand, if your method getById
is throwing FooConnectionTimeoutException, FooConnectionPoolExhaustedException, FooTableNotFoundException, FooServiceObjectNotFoundException
, clearly something is not right about this either. But fear no more, my good OP! There is a solution.
You can organize exceptions by type, then throw a reasonably generic exception for each type possible. In other words, have FooConnectionTimeoutException, FooConnectionPoolExhaustedException, FooTableNotFoundException
all derive from FooDatabaseException
. Your method signature then becomes:
getById(int id) throws FooServiceObjectNotFoundException, FooDatabaseException;
See how nice this is? Callers wanting to cover any and all exceptions would look no further than handling just FooServiceObjectNotFoundException
and FooDatabaseException
. Callers wanting to perform a different action upon FooServiceObjectNotFoundException
can do so no qualms.
You can further organize according to necessity if you want to be more detailed, but the level of detail is entirely up to you. The key point here being that you have full control over how specific you want your exceptions to be. As a general rule, try to reduce the number of exceptions thrown to 3 or less. Anything beyond that is somewhat unnecessary, especially if many of the exceptions are related to the same type of issue (unexpected problems, business errors, invalid input, etc.).