【问题标题】:Best practices for catching Throwable in Java在 Java 中捕获 Throwable 的最佳实践
【发布时间】:2009-07-08 11:35:59
【问题描述】:

有时,您只需要捕获 Throwable,例如在编写调度通用项目并需要从任何错误中恢复的调度程序队列时(所述调度程序记录所有捕获的异常,但静默,然后在其他项目上继续执行)。

我能想到的一个最佳实践是,如果异常是 InterruptedException,则始终重新抛出异常,因为这意味着有人中断了我的线程并想要杀死它。

另一个建议(来自评论,而不是答案)是总是重新抛出ThreadDeath

还有其他最佳做法吗?

【问题讨论】:

  • ThreadDeath 也应该被重新抛出,但它不应该被抛出。
  • 为什么要评论,这正是我想要的答案?

标签: java exception throwable


【解决方案1】:

可能最重要的是,永远不要吞下已检查的异常。我的意思是不要这样做:

try {
  ...
} catch (IOException e) {
}

除非你打算这样做。有时人们会接受已检查的异常,因为他们不知道如何处理它们,或者不想(或不能)用“抛出异常”子句来污染他们的界面。

如果您不知道如何处理它,请执行以下操作:

try {
  ...
} catch (IOException e) {
  throw new RuntimeException(e);
}

另一个想到的是确保您处理异常。读取文件应该是这样的:

FileInputStream in = null;
try {
  in = new FileInputStream(new File("..."));;
  // do stuff
} catch (IOException e) {
  // deal with it appropriately
} finally {
  if (in != null) try { in.close(); } catch (IOException e) { /* swallow this one */ }
}

【讨论】:

  • +1 表示永远不会吞下已检查的异常 - 即使在您的“第一次通过”中也是如此。这些事情经常被忽视并最终提交给源代码控制。如果有疑问,至少打印堆栈跟踪。
  • 如果你不能处理它并且不能重新抛出它,至少打印那个堆栈跟踪!日志中的堆栈跟踪对诊断问题有很大帮助。
  • 检查异常的可怕之处......捕获 IOException 只是为了将其包装在一个非检查异常中并且根本不对它做任何事情?当然,这就是你在 Java 中必须做的事情,除非你真的知道为什么会得到异常。
  • -1 问题是关于捕获可抛出对象和最佳技术,而不是关于吞下检查的异常。
  • Java 什么时候添加了 catch(Throwable) ?还是它一直存在而我不知道?
【解决方案2】:

取决于你在做什么。

如果您正在开发供其他人使用的 API,最好重新抛出异常或将其包装到您的自定义异常中并抛出。

而如果您正在开发最终用户应用程序,则需要处理此异常并做必要的事情。

【讨论】:

    【解决方案3】:

    OutOfMemoryError(或者它的超类 VirtualMachineError)呢?我无法想象在发生这么严重的事情之后你还能做些什么。

    【讨论】:

    • 如果分配大量对象的线程碰巧在分配的对象变为可垃圾回收的位置捕获 OutOfMemoryError,则 VM 可以恢复。如果对象仍然被引用,那么是的,除了退出或释放一些对象之外,您无能为力。
    • Catch VirtualMachineError 很棘手,因为您的程序处于未定义状态:stackoverflow.com/questions/8728866/…
    【解决方案4】:

    如果您正在编写调度程序队列,那么当异常返回给您时,除了记录它之外,对它做任何事情都没有意义。 Swing 事件队列基本上具有这种类型的行为。

    或者,您可以为“未捕获的异常处理程序”提供一个挂钩,类似于ThreadGroup。请注意,处理程序可能需要很长时间,最终会延迟您的调度程序。

    就 InterruptedException 而言:唯一关心的是您的调度循环,它应该检查一些外部状态以查看它是否应该停止处理。

    【讨论】:

    • 为什么检查外部状态比使用 InterruptedException 作为信号机制更好?
    • 因为 InterruptedException 只是表明有人在线程上调用了 interrupt()。这样做可能有多种原因,而不仅仅是终止当前操作。如果您确实想使用 interrupt() 来终止调度程序,您当然不想抛出它;只需从 run() 返回——当然,除非你的调度程序不是线程唯一在做的事情,但即使在那里,你也几乎肯定不想盲目地抛出。
    猜你喜欢
    • 1970-01-01
    • 2015-02-11
    • 2010-09-15
    • 1970-01-01
    • 2020-03-22
    • 2010-09-08
    • 2011-02-24
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多