重新抛出 Exception 的原因是否可以接受?
Is it acceptable to rethrow Exception's cause?
有时我想向用户抛出一个包含更多信息的异常,这样他们就可以很容易地看出方法失败的原因。
我的方法如下所示:
public myPublicMethod(...) throws Exception1, Exception2 {
try {
doSomething(); // this throws OtherException
}
catch (OtherException e) {
Exception cause = e.getCause()
if (cause instanceof Exception1) {
throw (Exception1) cause;
}
if (cause instanceof Exception2) {
throw (Exception2) cause;
}
throw new IllegalStateException("some other type of exception occurred", cause);
}
}
这样的设计可以接受吗?
你的想法很好,但是依我拙见,你的实现方式有点不对劲,我会尽力解释的。
您一开始就声称要为用户提供有关异常的更多信息。你做了什么 - 从它的“父异常”中剥离原因(e.getCause()
然后抛出原因) - 实际上给用户 less 信息,因为 [=11] 中的信息=],您丢弃的可能包含有关导致程序崩溃的流程的有用详细信息。
- 捕获最具体的异常并将其抛给调用者是一种很好的做法,但请确保您没有遗漏细节。抛出cause而没有parent exception,其实是省略了细节。
- 有时包装您捕获的异常并提供更多有关它的详细信息(就像您在最后一行中打算做的那样)是有意义的,但再次确保您只是 添加细节,不漏细节
您可以阅读有关异常处理最佳实践的更多信息here。
I would want to throw an exception with more information
通过使用自定义或 built-in 异常和 re-throwing.
来捕获异常以提供额外信息的做法没有错
我认为如果您只想对有限类型的异常执行此操作,方法是用 IllegalStateException
包装并添加自定义消息并保留异常原因。但是有一个 警告 :OtherException
的类型不应该太宽泛,就像一般的 Exception
,这样它只会包含有限数量的异常类型.
但是 re-throwing 只是一个原因 就像你对 Exception1
或 Exception2
所做的那样看起来很可疑。出于某种原因,您不认为它们是 root-cases 并且会对它们可以携带的信息视而不见。这听起来像是一个设计缺陷。还要记住,原因可能是 null
(在这种情况下,异常不会包装任何东西)并且此代码将失败并返回 NullPointerException
。因此,在下面的示例中,相同的异常将得到 re-thrown 而不是 re-throwing 原因。
从clean-coding的角度来说,尽量少用type-checks比较好。我认为在这种情况下你不需要求助于 instanceof
检查。
相反,您可以利用异常处理机制提供的功能。
由于你需要执行相同的操作(re-throw捕获到的异常)如果发生Exception1
或Exception2
,如果类型 Exception1
或 Exception2
是 siblings(即它们不会 extend 彼此),这些异常可以被处理使用 multi-catch clause 以避免代码重复:
catch (Exception1 | Exception2 e) {
throw e;
}
否则,如果假设 Exception2
是 Exception1
的子类型,那么您应该从更具体的类型开始在单独的 catch
块中处理它们,即 subtype 应该在 supertype:
之前处理
catch (Exception2 e) {
throw e;
}
catch(Exception1 e) {
throw e;
}
然后添加一个 catch
子句,其类型最少(比之前定义的所有异常类型更宽),以处理可能通过抛出 [= 的新实例而发生的所有其他异常类型13=].
示例:
public void myPublicMethod(Path source, Path destination)
throws FileAlreadyExistsException, DirectoryNotEmptyException {
try {
Files.copy(source, destination);
// do some other actions
}
catch (FileAlreadyExistsException | DirectoryNotEmptyException e) {
throw e;
}
catch (IOException e) {
throw new IllegalStateException("some other type of exception occurred", e);
}
}
有时我想向用户抛出一个包含更多信息的异常,这样他们就可以很容易地看出方法失败的原因。
我的方法如下所示:
public myPublicMethod(...) throws Exception1, Exception2 {
try {
doSomething(); // this throws OtherException
}
catch (OtherException e) {
Exception cause = e.getCause()
if (cause instanceof Exception1) {
throw (Exception1) cause;
}
if (cause instanceof Exception2) {
throw (Exception2) cause;
}
throw new IllegalStateException("some other type of exception occurred", cause);
}
}
这样的设计可以接受吗?
你的想法很好,但是依我拙见,你的实现方式有点不对劲,我会尽力解释的。
您一开始就声称要为用户提供有关异常的更多信息。你做了什么 - 从它的“父异常”中剥离原因(e.getCause()
然后抛出原因) - 实际上给用户 less 信息,因为 [=11] 中的信息=],您丢弃的可能包含有关导致程序崩溃的流程的有用详细信息。
- 捕获最具体的异常并将其抛给调用者是一种很好的做法,但请确保您没有遗漏细节。抛出cause而没有parent exception,其实是省略了细节。
- 有时包装您捕获的异常并提供更多有关它的详细信息(就像您在最后一行中打算做的那样)是有意义的,但再次确保您只是 添加细节,不漏细节
您可以阅读有关异常处理最佳实践的更多信息here。
I would want to throw an exception with more information
通过使用自定义或 built-in 异常和 re-throwing.
来捕获异常以提供额外信息的做法没有错我认为如果您只想对有限类型的异常执行此操作,方法是用 IllegalStateException
包装并添加自定义消息并保留异常原因。但是有一个 警告 :OtherException
的类型不应该太宽泛,就像一般的 Exception
,这样它只会包含有限数量的异常类型.
但是 re-throwing 只是一个原因 就像你对 Exception1
或 Exception2
所做的那样看起来很可疑。出于某种原因,您不认为它们是 root-cases 并且会对它们可以携带的信息视而不见。这听起来像是一个设计缺陷。还要记住,原因可能是 null
(在这种情况下,异常不会包装任何东西)并且此代码将失败并返回 NullPointerException
。因此,在下面的示例中,相同的异常将得到 re-thrown 而不是 re-throwing 原因。
从clean-coding的角度来说,尽量少用type-checks比较好。我认为在这种情况下你不需要求助于 instanceof
检查。
相反,您可以利用异常处理机制提供的功能。
由于你需要执行相同的操作(re-throw捕获到的异常)如果发生Exception1
或Exception2
,如果类型 Exception1
或 Exception2
是 siblings(即它们不会 extend 彼此),这些异常可以被处理使用 multi-catch clause 以避免代码重复:
catch (Exception1 | Exception2 e) {
throw e;
}
否则,如果假设 Exception2
是 Exception1
的子类型,那么您应该从更具体的类型开始在单独的 catch
块中处理它们,即 subtype 应该在 supertype:
catch (Exception2 e) {
throw e;
}
catch(Exception1 e) {
throw e;
}
然后添加一个 catch
子句,其类型最少(比之前定义的所有异常类型更宽),以处理可能通过抛出 [= 的新实例而发生的所有其他异常类型13=].
示例:
public void myPublicMethod(Path source, Path destination)
throws FileAlreadyExistsException, DirectoryNotEmptyException {
try {
Files.copy(source, destination);
// do some other actions
}
catch (FileAlreadyExistsException | DirectoryNotEmptyException e) {
throw e;
}
catch (IOException e) {
throw new IllegalStateException("some other type of exception occurred", e);
}
}