如果您想以相同的方式处理每个故障,例如通过记录它并跳到下一个请求,向用户显示消息并处理下一个事件等,未经检查的异常是可以的。如果这是我的用例,我必须做的是在我的系统中捕获一些高级别的一般异常类型,并以相同的方式处理所有事情。
但我想从特定问题中恢复过来,我不确定用未经检查的异常处理它的最佳方法。这是一个具体的例子。
假设我有一个使用 Struts2 和 Hibernate 构建的 Web 应用程序。如果我的“动作”出现异常,我会记录下来,并向用户表示歉意。但是我的 Web 应用程序的功能之一是创建新的用户帐户,这需要一个唯一的用户名。如果用户选择了一个已经存在的名称,Hibernate 会org.hibernate.exception.ConstraintViolationException
在我的系统内部抛出一个(未经检查的异常)。我真的很想通过要求用户选择另一个用户名来从这个特定问题中恢复过来,而不是给他们同样的“我们记录了你的问题,但现在你已经被淹没了”的消息。
这里有几点需要考虑:
- 有很多人同时创建帐户。我不想在“SELECT”之间锁定整个用户表以查看名称是否存在,如果不存在则“INSERT”。在关系数据库的情况下,可能有一些技巧可以解决这个问题,但我真正感兴趣的是由于基本竞争条件而无法预先检查异常的一般情况。同样的事情也适用于在文件系统上查找文件等。
- 考虑到我的 CTO 倾向于通过阅读“Inc.”中的技术专栏来进行偷渡式管理,我需要围绕持久性机制设置一层间接层,这样我就可以抛弃 Hibernate 并使用 Kodo 或其他任何东西,而不需要更改任何东西,除了最低的持久化代码层。事实上,在我的系统中有几个这样的抽象层。尽管有未经检查的异常,如何防止它们泄漏?
- 已检查异常的一个公认的弱点是必须在堆栈上的每次调用中“处理”它们——要么通过声明调用方法抛出它们,要么通过捕获它们并处理它们。处理它们通常意味着将它们包装在另一个适合抽象级别的类型的检查异常中。因此,例如,在检查异常领域,我的 UserRegistry 的基于文件系统的实现可能会 catch
IOException
,而数据库实现会 catchSQLException
,但两者都会抛出UserNotFoundException
隐藏底层实现的 a。如何利用未经检查的异常,在不泄露实现细节的情况下减轻每一层包装的负担?