捕捉Throwable是不好的做法?

捕捉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之后,您的代码的行为在很大程度上是未定义的。

捕获exception会发生类似的问题。 也许getUserInput()失败是因为InterruptException,或者在尝试logging结果时拒绝了一个权限exception,或者是所有其他types的失败。 你不知道出了什么问题,因此你也不知道如何解决这个问题。

你有三个更好的select:

1 – 抓住你知道如何处理的例外:

 try { inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() ); } catch(ParseException e) { inputNumber = 10; //Default, user did not enter valid number } 

2 – 重申您遇到的任何exception,不知道如何处理:

 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); } 

另外请注意,当你捕获Throwable ,你也可以捕获InterruptedException ,这需要特殊的处理。 有关更多详细信息,请参阅处理InterruptedException 。

如果你只想捕获未经检查的exception,你也可以考虑这种模式

 try { ... } catch (RuntimeException exception) { //do something } catch (Error error) { //do something } 

这样,当你修改你的代码并添加一个可以抛出检查exception的方法调用时,编译器会提醒你,然后你可以决定为这种情况做些什么。

直接从Error类的javadoc(build议不要捕获这些):

  * 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 

如果你绝对不能有一个exception冒泡的方法,这不是一个坏习惯。

如果你真的不能处理这个例外,这是一个糟糕的做法。 更好的方法签名添加“抛出”,而不是只是捕获和重新抛出,或者更糟糕的是,将其包装在RuntimeException中并重新抛出。

如果您使用过度热情地抛出错误的库,捕捉Throwable有时是必需的,否则您的库可能会终止您的应用程序。

但是,在这种情况下最好只指定库引发的特定错误,而不是所有的Throwables。

这取决于你的逻辑或对你的select/可能性更具体。 如果有什么特别的例外,你可以用有意义的方式作出反应,那么你可以先抓住它,然后这样做。

如果没有,并且你确定你会为所有的exception和错误(例如退出一个错误消息)做同样的事情,那么赶上throwable就没有问题了。

通常情况下,第一种情况下,你不会赶上抛出。 但是,仍然有很多情况下捕捉它的工作正常。

Throwable是所有类的基类,可以抛出(不仅是例外)。 如果你捕捉到OutOfMemoryError或者KernelError,你几乎没有办法做(请参阅何时捕获java.lang.Error? )

捕捉exception应该足够了。

虽然它被描述为一个非常糟糕的做法,但是有时你可能会发现罕见的情况,它不仅有用而且是强制性的。 这里有两个例子。

在Web应用程序中,您必须向用户显示完整的错误页面。 这段代码确保这一切发生,因为它是围绕所有请求处理程序(servlet,struts操作或任何控制器….)

 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); } 

但是,如果发生任何exception会发生什么? 你不应该停下来,因为一个转移可能是成功的,一个转移可能不成功,你应该继续通过所有的用户List ,并显示每个转移的结果。 所以你最终得到这个代码。

 for(FundTransferVO fundTransferVO : fundTransferVOList){ FoundtransferService.doTransfer( foundtransferVO); }catch(Throwable ex){ LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex); } } 

你可以浏览大量的开源项目,看看这个throwable真的被caching和处理。 例如这里是一个searchtomcatstruts2primefaces

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通常是不好的做法(正如在这个问题上的众多答案所阐明的那样),捕获Throwable的场景是很常见的。 让我解释一个这样的案例,我用我的工作,一个简单的例子。

考虑一种方法,执行两个数字的添加,并且在成功添加之后,它向特定的人发送电子邮件警报。 假设返回的数字是重要的,并被调用方法使用。

 public Integer addNumbers(Integer a, Integer b) { Integer c = a + b; //This will throw a NullPointerException if either //a or b are set to a null value by the //calling method successfulAdditionAlert(c); return c; } private void successfulAdditionAlert(Integer c) { try { //Code here to read configurations and send email alerts. } catch (Throwable e) { //Code to log any exception that occurs during email dispatch } } 

发送电子邮件警报的代码读取了大量的系统configuration,因此可能会从该代码块中抛出各种exception。 但是,我们不希望在警报调度期间遇到任何exception传播到调用方法,因为该方法只关心它提供的两个整数值的总和。 因此,派发电子邮件警报的代码被放置在try-catch块中,其中Throwable被捕获,并且仅logging任何exception,从而允许剩余的stream程继续。

如果我们使用throwable ,那么它也覆盖了Error ,就是这样。

例。

  public class ExceptionTest { /** * @param args */ public static void m1() { int i = 10; int j = 0; try { int k = i / j; System.out.println(k); } catch (Throwable th) { th.printStackTrace(); } } public static void main(String[] args) { m1(); } 

}

输出:

 java.lang.ArithmeticException: / by zero at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12) at com.infy.test.ExceptionTest.main(ExceptionTest.java:25) 

Throwable是所有错误和优先级的超类。 如果在catch子句中使用Throwable,它不仅会捕获所有exception,还会捕获所有错误。 JVM抛出错误,指出不应该由应用程序处理的严重问题。 典型的例子是OutOfMemoryError或者StackOverflowError。 两者都是由应用程序控制之外的情况引起的,无法处理。 所以你不应该捕捉Throwables,除非你确信它只是Throwable中的一个exception。