烦人的异常

无论是否有异常处理,用任何语言编写良好的错误处理代码都是困难的。当我考虑在一个给定的程序中需要实现什么样的异常处理时,我首先将可能捕获的每个异常分类到四个bucket中的一个,我将其标记为致命的、硬骨头般突出的、烦人的、外部的。

致命的异常不是你的错,你不能阻止它们,你也不能理智地清除它们。它们几乎总是发生,因为这一进程病入膏肓,即将摆脱痛苦。内存不足、线程中止等。捕捉这些是毫无意义的,因为你的用户代码所能做的一切都不能解决问题。就让你的“finally”块运行,并希望最好的。(或者,如果你真的很担心,快速失败和不让;在这一点上“finally”块运行,它们可能只会让事情变得更糟。但这是另一话题。)

硬骨头般突出的异常是您自己的该死的错误,您可以阻止它们,因此它们是代码中的错误。你不应该捕获它们;这样做是在你的代码中隐藏了一个错误。相反,您应该改写您的代码,这样就不可能在第一时间发生异常,因此不需要捕获异常。这个参数是空的,类型转换是坏的,索引超出范围,你试图除以零-这些都是你本来可以很容易地避免的问题,所以首先要防止混乱,而不是试图捕获它。

令人烦恼的异常是不幸的设计决策的结果。恼人的异常是在完全非异常的情况下抛出的,因此必须一直捕获和处理。典型的异常例子是Int32.Parse,如果给它一个不能被解析为整数的字符串,它就会抛出。但是这个方法99%的用例是转换用户输入的字符串,这可能是任何旧的东西,因此解析失败也不例外。更糟糕的是,如果不实现整个方法本身,调用者就无法提前确定其参数是否糟糕,在这种情况下,他们不需要首先调用它。这个不幸的设计决策非常令人恼火,当然,框架团队随后不久就实现了TryParse,这是正确的做法。你必须抓住令人恼火的异常,但这样做是令人恼火的。试着永远不要自己写一个抛出令人烦恼的例外的库。

最后,外部异常看起来有点像恼人的异常,只是它们不是不幸的设计选择的结果。相反,它们是凌乱的外部现实影响到你美丽、清晰的程序逻辑的结果。考虑这个伪C#代码,例如:

try
{
using ( File f = OpenFile(filename, ForReading) )
{
// Blah blah blah
}
}
catch (FileNotFoundException)
{
// Handle filename not found
}

你能消除try-catch?

if (!FileExists(filename))
// Handle filename not found
else
using ( File f = ...

这不是同一个程序。现在出现了“种族状况”。其他进程可能已经删除、锁定、移动或更改了文件exists和OpenFile之间的文件权限。我们能更成熟点吗?如果我们锁定文件呢?那没用。媒体可能已从驱动器中删除,网络可能已关闭…。你必须抓住一个外生的异常,因为不管你多么努力地避免它,它总是可能发生的;它是你无法控制的外生条件。

下面总结一下:

  • 不要捕捉致命的异常;不管怎样,您都无法处理它们,并且通常会使情况变得更糟。
  • 修复代码,使其永远不会触发硬骨头般突出的异常-生产代码中永远不会发生“索引超出范围”异常。
  • 尽可能避免恼人的异常,方法是调用那些在非异常情况下抛出的恼人方法的“Try”版本。如果无法避免调用烦人的方法,请捕获其烦人的异常。
  • 始终处理表示意外外部条件的异常;通常,预测每一个可能的失败是不值得或不实际的。请尝试该操作并准备好处理异常。

猜你喜欢

转载自www.cnblogs.com/yilang/p/13024252.html