捕获 Throwable
是一种不好的做法吗?
例如像这样:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
这种做法是不好的吗,还是我们应该尽可能的具体明确?
捕获 Throwable
是一种不好的做法吗?
例如像这样:
try {
// Some code
} catch(Throwable e) {
// handle the exception
}
这种做法是不好的吗,还是我们应该尽可能的具体明确?
为了避免意外的错误,您需要尽可能具体。
此外,Throwable
包含 Error
,这通常是不可逆转的。您并不希望捕获 / 处理它,而是希望程序立即停止,以便您可以正确地修复它。
这是一个不好的想法。事实上,即使捕获Exception
也通常是一个不好的想法。让我们考虑一个例子:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
inputNumber = 10; //Default, user did not enter valid number
}
假设现在getUserInput()会阻塞一段时间,并且另一个线程以最坏的方式停止了你的线程(调用了thread.stop())。你的catch块将捕获ThreadDeath错误。这非常糟糕。在捕获该异常后,您的代码行为很大程度上是未定义的。
捕获Exception也存在类似的问题。也许getUserInput()由于InterruptException失败,或者在尝试记录结果时因权限被拒绝而失败,或者出现各种其他故障。由于这个原因,你不知道出了什么问题,也不知道如何解决问题。
你有三个更好的选择:
1 -- 只捕获你知道如何处理的异常:
try {
inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(ParseException e) {
inputNumber = 10; //Default, user did not enter valid number
}
2 -- 抛出你遇到但不知道如何处理的任何异常:
try {
doSomethingMysterious();
} catch(Exception e) {
log.error("Oh man, something bad and mysterious happened",e);
throw e;
}
3 -- 使用 finally 块,这样您就不必记住重新抛出异常:
Resources r = null;
try {
r = allocateSomeResources();
doSomething(r);
} finally {
if(r!=null) cleanUpResources(r);
}
throw new Exception("Some additional info, eg. userId " + userId, e);
。这将在一个漂亮的异常中记录10个原因。 - Petr Újezdský请注意,当你捕获Throwable
时,也可以同时捕获需要特殊处理的InterruptedException
。有关更多详细信息,请参见处理InterruptedException。
如果您只想捕获未经检查的异常,您也可以考虑此模式。
try {
...
} catch (RuntimeException exception) {
//do something
} catch (Error error) {
//do something
}
这样,当您修改代码并添加可能引发已检查异常的方法调用时,编译器会提醒您,并且您可以决定如何处理此情况。
直接从 Error 类的 Javadoc 中摘取(建议不要捕获这些异常):
* An <code>Error</code> is a subclass of <code>Throwable</code>
* that indicates serious problems that a reasonable application
* should not try to catch. Most such errors are abnormal conditions.
* The <code>ThreadDeath</code> error, though a "normal" condition,
* is also a subclass of <code>Error</code> because most applications
* should not try to catch it.
* A method is not required to declare in its <code>throws</code>
* clause any subclasses of <code>Error</code> that might be thrown
* during the execution of the method but not caught, since these
* errors are abnormal conditions that should never occur.
*
* @author Frank Yellin
* @version %I%, %G%
* @see java.lang.ThreadDeath
* @since JDK1.0
如果你绝对不能让一个方法抛出异常,那么这并不是一种不好的实践。
但如果你真的无法处理异常,那么这就是一种不好的实践。最好在方法签名中添加“throws”,而不是仅仅捕获并重新抛出异常,或者更糟糕的是将其包装在RuntimeException中并重新抛出。
Throwable
实例确实有绝对合法的情况 - 例如用于自定义异常日志记录。 - Yuriy Nakonechnyy如果你使用的库过度热衷于抛出Errors,有时就需要捕获Throwable,否则你的库可能会导致应用程序崩溃。
然而,在这种情况下,最好只指定库抛出的具体错误,而不是所有的Throwables。
try {
…
} catch(final Throwable throwable) {
connection.rollback();
throw throwable;
}
Throwable是所有可被抛出的类(不仅仅是异常)的基础类。如果你捕获了OutOfMemoryError或KernelError(请参见何时捕获java.lang.Error?),那么你能做的很少。
捕获异常应该足够了。
虽然这被描述为一种非常不好的做法,但在某些罕见的情况下,它不仅有用而且是必需的。以下是两个例子。
在必须向用户显示有意义的错误页面的Web应用程序中。此代码确保发生这种情况,因为它在所有请求处理程序(servlet、struts操作或任何控制器...)周围有一个大的try/catch
块。
try{
//run the code which handles user request.
}catch(Throwable ex){
LOG.error("Exception was thrown: {}", ex);
//redirect request to a error page.
}
以另一个例子为例,考虑您拥有一个服务类,用于处理资金转移业务。如果转移完成,则此方法返回TransferReceipt
;如果未能完成,则返回NULL
。
String FoundtransferService.doTransfer( fundtransferVO);
List
,而你必须使用上述服务来完成它们。for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}
但是,如果发生任何异常会怎么样呢?你不应该停止,因为可能有一个转账成功了,而另一个没有,你应该继续遍历所有用户List
,并将结果显示给每个转账。因此,您最终得到以下代码。
for(FundTransferVO fundTransferVO : fundTransferVOList){
FoundtransferService.doTransfer( foundtransferVO);
}catch(Throwable ex){
LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex);
}
}
throwable
确实被缓存和处理。例如,这里是对tomcat
、struts2
和primefaces
的搜索结果链接:
https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable
throwable
,这也是这个问题的关键。 - Alireza Fattahi