抓住Throwable是不好的做法?

ktu*_*nho 100 java exception-handling throwable

赶上是不好的做法Throwable

例如这样的事情:

try {
    // Some code
} catch(Throwable e) {
    // handle the exception
}
Run Code Online (Sandbox Code Playgroud)

这是一种不好的做法还是我们应该尽可能具体?

Bal*_*usC 92

你需要尽可能具体.否则不可预见的错误可能会以这种方式蔓延开来.

此外,还有Throwable封面Error,通常没有回报点.您不想捕获/处理它,您希望程序立即死亡,以便您可以正确地修复它.

  • 在某些情况下,捕获错误和继续是合适的.例如:在servlet中,如果因为特定请求碰巧占用了所有内存而进入OutOfMemoryError,则可以尝试继续,因为在处理请求后对象将是GC.断言错误也是如此.您不会关闭应用程序,因为请求中出现了问题. (38认同)
  • 我们遇到了NoSuchMethodError,幸好没有通过在部署后两周关闭服务器来取消所有客户.即.我们总是有一个捕捉Throwable并尽最大努力处理并向客户发送错误.毕竟,有许多类型的错误可以恢复,因为它可能只影响1000个客户中的1个. (10认同)
  • "*你希望你的程序立即死亡,以便你可以正确地修复它*"=>如果你的程序死了,你怎么知道发生了什么?捕获Throwable/Error来记录问题是一件合理的事情...... (10认同)
  • 你怎么知道分配的内容和OOME之前的内容?一旦你得到它,所有的赌注都会关闭,即使在像Tomcat或JBoss这样的J2EE容器中也是如此. (6认同)
  • @assylias一个独立的应用程序会给stderr带来致命的错误. (2认同)
  • @BalusC您应该在答案中反映这一点。所以蹩脚的软件永远不应该抓住 Throwable,但好的软件可以。 (2认同)

Bra*_*ugh 36

这是一个坏主意.事实上,即使是捕捉Exception通常也是一个坏主意.我们来看一个例子:

try {
    inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() );
} catch(Throwable e) {
    inputNumber = 10; //Default, user did not enter valid number
}
Run Code Online (Sandbox Code Playgroud)

现在,假设getUserInput()阻塞了一段时间,另一个线程以最坏的方式阻止你的线程(它调用thread.stop()).你的catch块会遇到ThreadDeath错误.这太糟糕了.捕获该异常后代码的行为很大程度上是未定义的.

捕获异常会出现类似的问题.可能getUserInput()因InterruptException或尝试记录结果时出现权限被拒绝异常或其他各种故障而失败.你不知道出了什么问题,因为那样,你也不知道如何解决这个问题.

你有三个更好的选择:

1 - 准确捕获您知道如何处理的异常:

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

2 - 重新抛出遇到的任何异常,并且不知道如何处理:

try {
    doSomethingMysterious();
} catch(Exception e) {
    log.error("Oh man, something bad and mysterious happened",e);
    throw e;
}
Run Code Online (Sandbox Code Playgroud)

3 - 使用finally块,这样您就不必记住重新抛出:

 Resources r = null;
 try {
      r = allocateSomeResources();
      doSomething(r);
 } finally {
     if(r!=null) cleanUpResources(r);
 }
Run Code Online (Sandbox Code Playgroud)

  • +1表示即使捕获异常也不好.至少有一个ThreadInterruptedException需要特别小心(简而言之 - 在捕获它之后,你必须将线程的中断状态设置回'true') (4认同)
  • 我认为选项#2 是不好的做法。想象一下 10 个带有 log & rethrow 的链式调用。如果你查看日志文件,你会不高兴。异常被记录了 10 次,使得日志很难阅读。恕我直言,更好的是做`throw new Exception("Some additional info, eg. userId " + userId, e);`。这将被记录在一个很好的异常中,有 10 个原因。 (2认同)

gaw*_*awi 19

另外请注意,当您捕获时Throwable,您还可以捕获InterruptedException哪些需要特殊处理.有关更多详细信息,请参阅处理InterruptedException.

如果您只想捕获未经检查的异常,则可能还会考虑此模式

try {
   ...
} catch (RuntimeException exception) {
  //do something
} catch (Error error) {
  //do something
}
Run Code Online (Sandbox Code Playgroud)

这样,当您修改代码并添加可以抛出已检查异常的方法调用时,编译器会提醒您,然后您可以决定如何处理此情况.


duf*_*ymo 13

如果你绝对不能从方法中获得异常气泡,这并不是一个坏习惯.

如果你真的无法处理异常,这是一个不好的做法.最好在方法签名中添加"throws",而不仅仅是catch和re-throw,或者更糟糕的是,将它包装在RuntimeException中并重新抛出.

  • 完全同意 - 处理所有`Throwable`实例的绝对合法案例 - 例如自定义异常日志记录. (10认同)

And*_*man 13

直接来自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
Run Code Online (Sandbox Code Playgroud)


DNA*_*DNA 9

如果你使用过度热情地抛出错误的库,有时候需要捕获Throwable,否则你的库可能会杀死你的应用程序.

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

  • 或者使用更好的书面库? (11认同)
  • 确实,如果你有选择;-) (6认同)

b.b*_*old 5

这取决于您的逻辑或更具体的选择/可能性.如果有任何特定的异常,您可以以有意义的方式做出反应,您可以先捕获它并执行此操作.

如果没有,并且您确定您将对所有异常和错误执行相同的操作(例如,使用错误消息退出),则捕获throwable不是问题.

通常第一种情况成立,你不会抓住扔掉的东西.但是仍有很多案例可以让它正常运行.


ic3*_*ic3 5

Throwable是所有类的基类,而不是可抛出的类(不仅仅是异常).如果你发现OutOfMemoryError或KernelError,你几乎无能为力(参见何时捕获java.lang.Error?)

捕获异常应该足够了.


Ali*_*ahi 5

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

在Web应用程序中,您必须向用户显示含义完整错误页面.此代码确保发生这种情况,因为它是try/catch围绕所有请求handeler(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. 
 }
Run Code Online (Sandbox Code Playgroud)

}

再举一个例子,考虑一下你有一个为资金转账业务提供服务的服务类.此方法返回TransferReceiptif传输完成或NULL不能传输.

String FoundtransferService.doTransfer( fundtransferVO);
Run Code Online (Sandbox Code Playgroud)

现在成像您List从用户获得资金转移,您必须使用以上服务来完成所有这些.

for(FundTransferVO fundTransferVO : fundTransferVOList){
   FoundtransferService.doTransfer( foundtransferVO);
}
Run Code Online (Sandbox Code Playgroud)

但是如果发生任何异常会发生什么?您不应该停止,因为一次转移可能是成功的而且可能不是,您应该继续通过所有用户List,并将结果显示给每次转移.所以你最终得到了这段代码.

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

您可以浏览许多开源项目,看看它throwable是否真的被缓存和处理.例如,这里是搜索tomcat,struts2primefaces:

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


Gar*_*son 5

这个问题有点含糊;您是在问“可以抓到吗Throwable”,还是“可以抓到一个Throwable而不做任何事”吗?这里的很多人都回答了后者,但这是一个附带问题;的99%的时间你不应该“消费”或放弃例外,无论你是赶上ThrowableIOException或什么的。

如果您传播异常,答案(就像对许多问题的答案一样)是“视情况而定”。这取决于您对异常所做的事情——为什么要捕获它。

为什么要捕获的一个很好的例子Throwable是,如果有任何错误,则提供某种清理。例如在 JDBC 中,如果在事务期间发生错误,您可能希望回滚事务:

try {
  …
} catch(final Throwable throwable) {
  connection.rollback();
  throw throwable;
}
Run Code Online (Sandbox Code Playgroud)

请注意,异常不会被丢弃,而是会传播。

但是作为一般策略,Throwable因为您没有理由并且懒得查看正在抛出哪些特定异常而进行捕获是一种糟糕的形式和一个坏主意。