假设我有接口I
和两个实现它的类A
和B
。
f
中此接口的方法A
的实现会抛出一组异常,而B
中的实现会抛出另一组异常。这些例外的唯一共同祖先是java.lang.Exception
。在这种情况下声明f
抛出java.lang.Exception
是否合理?还有其他选择吗?
我之所以要问的是,一方面java.lang.Exception
对我来说似乎太笼统,另一方面列出所有异常似乎不切实际,考虑到可能的其他实现。
示例:
interface I {
void f() throws Exception;
}
class A implements I {
public void f() throws IOException {}
}
class B implements I {
public void f() throws InterruptedException {}
}
答案 0 :(得分:16)
使用接口的原因是抽象出实现细节。
通过抛出这些异常,您将暴露可能应该被抽象出来的实现细节。
也许最好定义一个新的例外。然后f()的每个实现都会捕获它所知道的异常并抛出新的异常,所以你有:
interface I {
void f() throws MyException;
}
class A implements I {
public void f() throws MyException {
try {
...
} catch (IOException e) {
throw new MyException(e);
}
}
}
class B implements I {
public void f() throws MyException {
try {
...
} catch (InterruptedException e) {
throw new MyException(e);
}
}
}
通过包装实现异常,您仍然将它暴露给调用者,并且当您调用远程方法时可能会咬你。在这些情况下,您需要做更多工作以通用方式返回有用信息。
修改强>
关于正确的方法似乎存在一些争议。
当我们调用f()时,我们需要代码如下:
I instanceOfI = getI();
try {
instanceOfI.f();
}
catch ( /* What should go here ? */ )
归结为什么是一个好的Exception类放在catch块中
使用OP的原始代码,我们可以捕获Exception
,然后可能会尝试查看我们拥有哪个子类,或者根据需求。或者我们可以单独捕获每个子类,但是当新实现抛出不同的异常时我们必须添加catch块。
如果我们使用运行时异常,那么除了我们可以选择将异常处理推迟到调用方法而不考虑异常的可能性之外,它会发生相同的事情。
如果我们使用了使用新的包装异常的建议,那么这意味着我们必须捕获MyException
,然后尝试查看可用的其他信息。这基本上就像使用Exception一样,但需要额外的工作才能获得可以根据目的定制的bespoke
异常的有限好处。
答案 1 :(得分:3)
这似乎有点落后。您应该抛出与您的界面相关且可能特定的异常,或者根本不抛出异常。更改实现以包装常见的Exception类(尽管不是Exception
本身)。如果你不能处理这个问题,你可能想用RuntimeException包装实现中的异常。
答案 2 :(得分:1)
你可以宣布你抛出的例外
void f() throws IOException, InterruptedException;
如果您使用体面的IDE,它会为您纠正此问题。我只是在方法中抛出异常,IDE给出了将option添加到method子句及其接口的选项。