处理致命异常的位置在哪里?

3
我正在考虑一种设计,在Swing应用程序中使用自定义UncaughtExceptionHandler来处理所有致命异常。 这将包括未预期的RuntimeExceptions,但也包括在关键资源不可用或失败(例如找不到设置文件或服务器通信错误)时抛出的自定义异常。 根据特定的自定义异常(以及所有未预期的异常),UncaughtExceptionHandler会执行不同的操作,但在所有情况下应用程序都会向用户显示错误消息并退出。 另一种选择是为所有未预期的异常保留UncaughtExceptionHandler,但在其原始位置附近处理所有其他致命情况。
我正在考虑的设计合理吗?还是应该使用另一种方法? 处理致命异常的典型方法是什么?

我认为Bruce Eckel的文章非常有启发性 - http://www.mindview.net/Etc/Discussions/CheckedExceptions。我建议你仔细阅读它。基本上,使用未检查的异常并在顶层(即中央位置)处理它们。但是当必要时,您也可以在生成异常的地方处理它们。 - Sripathi Krishnan
感谢这篇好文章。我的背景是C#,所以Java的已检查异常对我来说一直是个挑战。虽然不太美观,但我学到了很多人建议的方法,即在没有任何有意义的方式处理它们的情况下,将已检查异常包装并重新抛出为RuntimeException通常是最佳策略(而不是在调用堆栈中添加throws声明或仅将其吞噬)。我认为本文展示的ExceptionAdapter有点过时了,因为Java 5引入了Throwable.getSource()方法。 - Stephen Swensen
只是想澄清一下,我想知道当我确实想要处理某些异常时,是否应该在源头处处理它们,还是将其包装并重新抛出为自定义运行时异常,并使用顶层处理程序检测和处理它们。 - Stephen Swensen
4个回答

2
通常,很难找到一个好的异常处理策略。每种方法都有其缺点。特别地,您提出的方法在某种程度上是不错的(集中处理失败),但存在以下缺陷:
您描述的异常处理程序将对每个可能的异常进行特殊处理。随着时间的推移,它将成为您应用程序的焦点:每次添加新功能时,您还需要向处理程序添加异常处理逻辑。这意味着:
1. 处理程序高度依赖于其他部分,某些功能实现的更改可能会触发处理程序的相应更改。您需要小心保持这两者同步。
2. 处理程序的一致性差(有许多更改原因)-它包含您应用程序所有功能的交集。
另一个问题是错误恢复。在抛出异常后(并呈现了某些通知给用户),用户希望继续使用应用程序。这意味着,如果您的代码开始修改内部数据结构,然后由于异常而停止,您需要撤消这些修改(或者至少使数据结构恢复到可工作状态)才能允许用户进行额外的交互。实现这一点需要重新考虑数据组织方式。一种可能的解决方案是使用数据库事务。另一方面,这种表示比普通的数据结构更复杂,因此您需要权衡一下其与应用程序需求的关系(它是玩具/原型吗?)。

谢谢您的反馈。您所描述的缺陷正是我担心的,听到您详细说明非常有帮助(我可能会放弃中央集权的方法)。我现在会保持这个问题的开放状态,欢迎其他人的意见,但明天我会回来并很可能将您的答案标记为最佳答案(除非出现其他超级有说服力的答案)。 - Stephen Swensen

1

我在一个大型的Swing应用程序中成功地使用了本地处理和集中处理的混合。集中处理只处理了我记得有两到三种特定类型以及所有未捕获的异常。已经过了一段时间,所以我不记得所有的细节,但我们最终得到了一个负责处理两到三种特定类型异常和所有未捕获异常的集中处理器。

我们在可能的情况下使用本地处理,同时也定义了类似于ErrorMessageException的东西,它可以从不与UI交互的后台线程中抛出。这个异常在中央处理器中有一个特定的处理方式。我们并不认为这是最美的解决方案,但它简单易行,并且效果很好。

任何未捕获的异常都被处理为"一般错误"或类似的内容。效果很好,当然我们努力发布没有引起任何未处理异常的代码。然而,在测试中,这是一个非常有帮助的功能。

采用这种方法,集中处理器容易维护,并且不会意外增长。事实上,我们没有看到任何紧密耦合的迹象,相反地。


0

main方法的逻辑包装在trycatch块中会更加直观;例如:

public static void main(String[] args) {
    try {
        // everything happens here
        System.exit(0);
    } catch (SpecificException ex) {
        ...
    } catch (AnotherException ex) {
        ...
    } catch (Throwable ex) {
        // deal with anything else.
        ...
    }
    System.exit(1);  // tell the world that we failed.
}

感谢您的回复。问题在于它无法捕获发生在Swing事件分派线程上的异常。然而,我更关心的是是否明智地设计了顶级异常处理程序(其中我正在创建一些异常)。 - Stephen Swensen

0

如果您有一个多线程应用程序(如大多数Swing应用程序),您可能希望通过某些异步队列将异常发送到中央异常处理线程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接