Say I'm dealing with forced to use a library API method that throws some sort of nondescript base exception; for example "throws Exception" in Java. Assume I do not have the option to modify the library source and I must deal with the base exception any time I call the API method from my own methods. For some context, my code might look like this without intervention:
public void myMethod() throws Exception { // I don't want to do this.
someAPIObject.theirMethod(); // API method throwing base exception.
}
And here might be the API method I'm calling in to:
public void theirMethod() throws Exception { // This is my problem.
// Does stuff that could cause problems, but is
// lazy and implicitly throws base exception.
// Now it's my problem!
}
My question is: how do I best go about dealing with this base exception being thrown at my methods? I assume it is in my best interest to somehow preserve all of the original exception information while propagating something more useful than a base exception. For example, I've considered catching and storing the base exception in my own exception type and throwing that instead:
public void myMethod() {
try {
someAPIObject.theirMethod(); // API method throwing base exception.
} catch (Exception e) {
throw new MySpecificException(e); // Re-throw my own exception.
}
}
I'm not looking for opinions but rather some solid and straightforward evidence (pros) as to why a particular solution is a good solution, as well as any cavaets (cons). My focus is on Java, but I am curious of any general concepts or "best-practices".
Throwing an exception is as simple as using the "throw" statement. You then specify the Exception object you wish to throw. Every Exception includes a message which is a human-readable error description. It can often be related to problems with user input, server, backend, etc.
When an exception is thrown the method stops execution right after the "throw" statement. Any statements following the "throw" statement are not executed.
Java catch block is used to handle the Exception by declaring the type of exception within the parameter. The declared exception must be the parent class exception ( i.e., Exception) or the generated exception type. However, the good approach is to declare the generated type of exception.
This question will undoubtedly be closed as "Too Broad" or "Opinion Based" but I'll throw in my 2c before it does.
Your second code sample should (nearly) always be the way to go:
public void myMethod() {
try {
someAPIObject.theirMethod(); // API method throwing base exception.
} catch (Exception e) {
throw new MySpecificException(e); // Re-throw my own exception.
}
}
My primary reason for this is that I do not want a leaky abstraction. For example, say I have some kind of repository for accessing users with the following interface:
public interface UserRepository {
public User byId(UserId id);
}
And I have this implemented by a MySql database, so have the following concrete class:
public class MySqlUserRepository implements UserRepository {
public User byId(UserId id);
}
Inside this class I will be needing to handle JDBC exceptions. If I just let them propagate through the interface, like this:
public interface UserRepository {
public User byId(UserId id) throws SqlException;
}
Then a client of my code now knows it is using JDBC in the background. If I wrap this, like you have, then the underlying data store is completely encapsulated, which is one of the points of having an abstraction in the first place. If I provide an implementation that uses some other datastore, e.g. Redis, then SqlException has no meaning anymore but I would need to update the contract to now make the methods throw the Exceptions that the specific datastore might throw.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With