什么更好/更快?使用try-catch还是避免异常?

16

我想知道在一般编程中,避免异常和等待异常哪个更好或更快?

避免异常的做法是:

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) ...

1
取消“更快”的字眼,它与此无关。而且这也不是使用try-catch的正确方式,因为你有点在挑战CLR。 - BoltClock
1
@BoltClock,不是这样的。如果发生异常,它会变慢。 - CaffGeek
1
@Chad:好的,没关系,不太相关。 - BoltClock
22
什么更好?通过正确饮食和运动来避免心脏病发作,还是故意引发心脏病,然后进行五重搭桥手术修复它?如果可以的话,总是总是要避免例外。本可以避免但未避免的异常情况是一个漏洞。 - Eric Lippert
实际上,如果只有一个条件需要满足并且可以避免错误,那么这是一个简单的问题,我们可以使用if else语句。也许你应该更好地提问,以便获得更好的答案。例如,如果您只能通过检查“很多事情,并且这些事情在计算上很昂贵”来检查是否抛出异常,或者难以实现,并且使用try catch操作可以有效跳过错误。在这种情况下,我应该使用try catch吗? - SKLTFZ
8个回答

21

在这里,性能不是最相关的问题。问题是,哪个更适合编写可读性强、易于维护和测试的程序。您可以稍后关注性能。

通常情况下,不要使用异常来进行流程控制。它们实际上是一种非局部的 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和非空。

然而,异常通常会在本地导致性能开销。它们是否会影响程序的性能(即成为瓶颈)是另一个问题。但是,如果使用得当,异常通常不会成为瓶颈(当应用程序崩溃时,谁会关心性能呢?)


是的,谢谢你的回答,我知道try和空catch不对劲。关于更易维护的程序,这是非常正确的。也许会发生其他意外的异常,而你永远不会知道。也许如果你不在乎可能发生的异常,只想继续运行程序,那么一个空的catch可能是有意义的。 - carlosdubusm
1
@carlosdumusm:你似乎理解得很正确,但我想指出的是,空的catch块或者捕获所有异常(即捕获基类Exception)的catch块是不好的,非常糟糕。你不知道可能会抛出什么类型的异常,但现在你声明可以处理所有异常。当事情变得糟糕时,但你不知道有多糟糕或者出了什么问题,因为你正在“处理”所有异常,继续下去可能非常危险。处理你知道自己能够处理的内容,否则就快速失败。 - jason
是的,很有道理。我有几年的编程经验,但对异常知识了解甚少,有时不知道在哪里使用try-catch或抛出异常。谢谢。 - carlosdubusm

8

异常是代价昂贵的——如果你能够测试并避免异常,请这么做。

异常不应该用于正常程序流程。


3
当然要避免异常,使用try catch会导致性能损失。

2

这要视情况而定。我几乎总是尽量避免异常,除非这样做代价太高。


1

从指令/性能角度来看,在一个重要的N运行时期内,避免是更昂贵的,因为您需要每次检查每个输入的长度。但有一个例外,catch分支只在那种情况下执行。


3
但是当它发生时,速度会变慢。它掩盖了其他可能的错误。这是一种糟糕的编程实践。 - CaffGeek
1
在正常流程中,Try-Catch不会产生任何开销?在示例中使用的测试和跳转似乎在处理时间方面相当便宜。 - Derrick
当出现空的 catch {} 时,这是可怕的编程实践,正如你所说,它掩盖了其他编程错误。并且如前所述,异常应该用于异常情况,而不是经常发生的情况(例如,如果您知道在初始化时列表总是为空,并且期望经常遇到它,则不再算是异常情况,并且您应该构建一个检查)。 - Aphex

0

抛出异常是一项昂贵的任务,因此我总是尝试验证而不是捕获。

这应该很容易测试,生成一些代码通过每次运行抛出异常并将其与执行条件检查的类似代码集进行测试,并测量性能。

如果代码记录了哪些条件会引发异常的详细信息,则应能够调整您的调用代码。当然,您无法处理每种情况(例如较低级别的运行时错误),因此您的代码只应在实际上可以做出反应并可能继续的情况下尝试处理异常。


0

除非没有替代方案,否则应仅将异常用于异常条件,因此只有在发生非常不寻常的情况并且仍然需要处理(弹出错误消息)时才应使用 try/catch。

使用 try/catch 还表明程序员可能会发生某些外部错误,并且需要处理。在您的示例中,list 为 null 只是程序执行/控制流程的正常部分,因此没有任何异常。

此外,空 catch-all 通常是一件不好的事(尽管有限的情况下需要)。它肯定需要一个注释来解释为什么您没有处理异常。

这里有一篇关于棘手异常的有用博客文章,您可能会发现有用


-1

如果可以避免异常,一定要避免。

异常应该是例外情况。

如果你能预测到它,就要防止它发生。

那些使用空catch块的人应该被禁止使用计算机...

不进入catch块也会更快。


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