我想知道在一般编程中,避免异常和等待异常哪个更好或更快?
避免异常的做法是:
string a = null;
list = someMethod();
if(list.Length > 0 ){
a = list[0];
}
if(a!=null) ...
或者尝试捕获异常...
string a = null;
try{
a = someMethod()[0];
catch{}
if(a!=null) ...
我想知道在一般编程中,避免异常和等待异常哪个更好或更快?
避免异常的做法是:
string a = null;
list = someMethod();
if(list.Length > 0 ){
a = list[0];
}
if(a!=null) ...
或者尝试捕获异常...
string a = null;
try{
a = someMethod()[0];
catch{}
if(a!=null) ...
在这里,性能不是最相关的问题。问题是,哪个更适合编写可读性强、易于维护和测试的程序。您可以稍后关注性能。
通常情况下,不要使用异常来进行流程控制。它们实际上是一种非局部的 goto
,使程序更难以阅读和跟踪。因此,它们应该保留给异常情况。如果您可以避免使用 try-catch
块进行流程控制,请不要使用。这样您的程序将更易读且易于维护。
处理这种情况的“正确”方法是
var list = someMethod();
if(list == null || list.Length == 0) {
// handle something bad
}
string a = list[0];
if(a != null) {
// go
}
如果someMethod
方法有一个合同(Contract.Ensures
)来保证返回值不为null且不为空,则可以避免检查list
是否为null和非空。
然而,异常通常会在本地导致性能开销。它们是否会影响程序的性能(即成为瓶颈)是另一个问题。但是,如果使用得当,异常通常不会成为瓶颈(当应用程序崩溃时,谁会关心性能呢?)
catch
块或者捕获所有异常(即捕获基类Exception
)的catch
块是不好的,非常糟糕。你不知道可能会抛出什么类型的异常,但现在你声明可以处理所有异常。当事情变得糟糕时,但你不知道有多糟糕或者出了什么问题,因为你正在“处理”所有异常,继续下去可能非常危险。处理你知道自己能够处理的内容,否则就快速失败。 - jason异常是代价昂贵的——如果你能够测试并避免异常,请这么做。
异常不应该用于正常程序流程。
这要视情况而定。我几乎总是尽量避免异常,除非这样做代价太高。
从指令/性能角度来看,在一个重要的N运行时期内,避免是更昂贵的,因为您需要每次检查每个输入的长度。但有一个例外,catch
分支只在那种情况下执行。
catch {}
时,这是可怕的编程实践,正如你所说,它掩盖了其他编程错误。并且如前所述,异常应该用于异常情况,而不是经常发生的情况(例如,如果您知道在初始化时列表总是为空,并且期望经常遇到它,则不再算是异常情况,并且您应该构建一个检查)。 - Aphex抛出异常是一项昂贵的任务,因此我总是尝试验证而不是捕获。
这应该很容易测试,生成一些代码通过每次运行抛出异常并将其与执行条件检查的类似代码集进行测试,并测量性能。
如果代码记录了哪些条件会引发异常的详细信息,则应能够调整您的调用代码。当然,您无法处理每种情况(例如较低级别的运行时错误),因此您的代码只应在实际上可以做出反应并可能继续的情况下尝试处理异常。
除非没有替代方案,否则应仅将异常用于异常条件,因此只有在发生非常不寻常的情况并且仍然需要处理(弹出错误消息)时才应使用 try/catch。
使用 try/catch 还表明程序员可能会发生某些外部错误,并且需要处理。在您的示例中,list 为 null 只是程序执行/控制流程的正常部分,因此没有任何异常。
此外,空 catch-all 通常是一件不好的事(尽管有限的情况下需要)。它肯定需要一个注释来解释为什么您没有处理异常。
这里有一篇关于棘手异常的有用博客文章,您可能会发现有用
如果可以避免异常,一定要避免。
异常应该是例外情况。
如果你能预测到它,就要防止它发生。
那些使用空catch块的人应该被禁止使用计算机...
不进入catch块也会更快。