在两种情况下,您应该捕获异常。
1. 在尽可能低的水平
这是您与第三方代码集成的级别,例如ORM工具或执行IO操作的任何库(通过HTTP访问资源,读取文件,保存到数据库,您可以命名它)。也就是说,将应用程序的本机代码留给与其他组件交互的级别。
在此级别,可能会发生您无法控制的意外问题,例如连接失败和文件锁定。
您可能希望通过捕获 来处理数据库连接失败,以便在几秒钟后重试。访问文件时的异常也是如此,该文件目前可能被进程锁定,但在下一刻可用。TimeoutException
此方案中的准则是:
-
仅处理特定异常,如 或 。从不处理泛型异常(类型
SqlTimeoutException
IOException
Exception
)
-
只有当您有有意义的事情要做时,才处理它,例如重试,触发补偿操作或向异常添加更多数据(例如上下文变量),然后重新抛出它
- 不在此处执行日志记录
-
让所有其他异常冒泡,因为它们将由第二种情况处理
2. 在尽可能高的水平上
这将是在将异常直接抛给用户之前可以处理异常的最后一个位置。
您在这里的目标是记录错误并将详细信息转发给程序员,以便他们能够识别并更正错误。添加尽可能多的信息,记录下来,然后向用户显示道歉消息,因为他们可能对此无能为力,特别是如果这是软件中的错误。
第二种情况下的准则是:
- 处理泛型异常类
- 从当前执行上下文中添加更多信息
- 记录错误并通知程序员
- 向用户道歉
- 尽快解决
这些准则背后的原因
首先,异常代表不可逆的错误。它们表示系统中的错误,程序员犯的错误或应用程序无法控制的情况。
在这些情况下,用户通常很少或根本无法执行任何操作。因此,您唯一能做的就是记录错误,采取必要的补偿措施,并向用户道歉。如果这是程序员犯的错误,最好让他们知道并修复它,努力实现更稳定的版本。
其次,尝试 catch
块可以屏蔽应用程序执行流,具体取决于它们的使用方式。块具有与 及其伴随块类似的功能,这会导致应用程序执行流从一个点跳转到另一个点。try catch
label
goto
何时引发异常
在开发库的上下文中更容易解释。当你遇到错误时,你应该抛出,除了让API的消费者知道它,让他们决定之外,你别无他法。
假设你是某个数据访问库的开发人员。当您遇到网络错误时,除了引发异常之外,您无能为力。从数据访问库的角度来看,这是一个不可逆转的错误。
当您开发网站时,这是不同的。您可能会捕获此类异常以进行重试,但如果您希望在从外层收到无效参数时引发异常,因为它们应该已在那里进行验证。
这在表示层中也有所不同,您希望用户提供无效的参数。在这种情况下,您只需显示友好的消息,而不是引发异常。
在 https://roaddd.com/the-only-two-cases-when-you-should-handle-exceptions/