说我正在处理 强制使用库API方法,该方法会抛出某种非描述性的基本异常;例如,在Java中“抛出异常”。假设我没有修改库源的选项,每次从我自己的方法调用API方法时,我都必须处理基本异常。对于某些上下文,我的代码看起来可能没有干预:
public void myMethod() throws Exception { // I don't want to do this.
someAPIObject.theirMethod(); // API method throwing base exception.
}
这里可能是我正在调用的API方法:
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!
}
我的问题是:我如何最好地处理这个基本异常被抛出我的方法?我认为以某种方式保留所有内容符合我的最佳利益传播比基本异常更有用的东西时的原始异常信息。例如,我已经考虑过捕获并将基本异常存储在我自己的异常类型中,然后抛出它:
public void myMethod() {
try {
someAPIObject.theirMethod(); // API method throwing base exception.
} catch (Exception e) {
throw new MySpecificException(e); // Re-throw my own exception.
}
}
我不是在寻找意见,而是寻找一些可靠且直截了当的证据(专业人士),为什么特定的解决方案是一个好的解决方案,以及任何cava(缺点)。我的重点是Java,但我对任何一般概念或“最佳实践”感到好奇。
答案 0 :(得分:3)
毫无疑问,这个问题将被视为“太宽泛”或“基于意见”,但我会在它之前投入我的2c。
你的第二个代码示例应该(几乎)始终是要走的路:
public void myMethod() {
try {
someAPIObject.theirMethod(); // API method throwing base exception.
} catch (Exception e) {
throw new MySpecificException(e); // Re-throw my own exception.
}
}
我的主要原因是我不想要leaky abstraction。例如,假设我有一些存储库用于访问具有以下界面的用户:
public interface UserRepository {
public User byId(UserId id);
}
我有一个MySql数据库实现,所以有以下具体类:
public class MySqlUserRepository implements UserRepository {
public User byId(UserId id);
}
在这个类中,我将需要处理JDBC异常。如果我让它们通过界面传播,就像这样:
public interface UserRepository {
public User byId(UserId id) throws SqlException;
}
然后我的代码的客户端现在知道它在后台使用JDBC。如果我像你一样包装它,那么底层数据存储是完全封装的,这是首先有一个抽象的点之一。如果我提供使用其他数据存储区的实现,例如Redis,然后SqlException没有任何意义,但我需要更新合同,现在让方法抛出特定数据存储可能抛出的异常。
答案 1 :(得分:2)
假设您知道API可以抛出的异常子类的完整列表,您可能最好通过运行时检查“破解”异常类型,并将该方法包装到引发特定异常的自己的包装器中。
以下是一个示例:假设API可以抛出Exception
的三个特定子类 - 即ExceptionOne
,ExceptionTwo
和ExceptionThree
。你可以构建一个这样的包装器:
class SomeApiWrapper {
public void myMethod() throws ExceptionOne, ExceptionTwo, ExceptionThree {
try {
someAPIObject.theirMethod();
} catch (Exception e) {
crackException(e);
}
}
private static void crackException(Exception e) throws ExceptionOne, ExceptionTwo, ExceptionThree {
if (e instanceof ExceptionOne) throw (ExceptionOne)e;
if (e instanceof ExceptionTwo) throw (ExceptionTwo)e;
if (e instanceof ExceptionThree) throw (ExceptionThree)e;
throw new RuntimeException("Caught an exception of unexpected type", e);
}
}
您的API的用户不必捕获Exception
(这是一件非常糟糕的事情),并保留原始异常中嵌入的所有信息。