嘿大家, 关于try..catch块的快速问题。我听说它们使用起来很昂贵,不应该用作程序流程的一部分。但是,为了验证电子邮件地址,我使用以下代码。可能重复:
Do try/catch blocks hurt performance when exceptions are not thrown?
try
{
MailAddress checkEmail = new MailAddress(testEmail);
return true;
}
catch
{
return false;
}
由于事先验证,除非是试图绕过验证,否则我没有多少例外被捕获。我的问题是,尝试...如果捕获到异常,Catch块只会很昂贵,或者无论是否抛出任何异常,总是昂贵?
谢谢
编辑:感谢所有回复。我已经决定,因为检查(在C#中)不是很昂贵,我会坚持使用这种方法。这主要是因为抛出的实际异常很少,因为先前的验证步骤确保没有人意外输入无效的电子邮件地址。
答案 0 :(得分:20)
在 general 中,在今天的实现中,输入try
块并不昂贵(这并非总是如此)。但是,抛出和处理异常通常是一项相对昂贵的操作。因此,异常通常应用于异常事件,而不是正常的流量控制。
性能只是需要考虑的一个因素,尤其是在现代世界。如果(例如)你正在做一次响应用户操作的事情,那么从性能角度来看,即使你可以进行主动检查,你是否使用异常并不重要,只要异常发生得足够快用户不是jolted.¹但是如果你在一个紧凑的循环中做一些事情会运行数十万次,或者你正在编写一个可能需要处理巨大负载的web应用程序,你可能我希望避免在正常情况下使用例外。
¹十多年前,我负责增强.Net 1.1“无触摸部署”应用程序,其中第一次抛出异常需要三秒钟。在一个用例中涉及打开文件时,这是一个足够的问题,用户要求的文件可能合理地不存在,我必须在尝试打开文件之前添加对文件存在的检查,这通常是糟糕的编程习惯(只是尝试打开文件并处理异常(如果失败),纯粹是因为等待该异常构建的用户体验非常糟糕。但那可能不是我们现在生活的世界。
答案 1 :(得分:2)
除非有例外情况,否则它们相当便宜。因此,当您需要例外时,应该避免使用它们,如上例所示。
我认为不良用户输入的例外通常是不明智的。内存不足或其他意外故障的例外情况很好。
答案 2 :(得分:2)
只是为了扮演恶魔倡导者 - 我发现使用Exceptions进行流量控制非常有用:“取消”按钮。
如果你的某个服务上运行的函数可能需要10-120分钟,这会做很多不同的事情,我发现if(hasCanceled)在我的Log()中抛出新的JobCancelledException()功能(记录我正在的每一步)只是为了工作而感到非常棒。它摆脱了当前代码的执行并停止运行作业 - 正是我需要的。我确信有一些更好的方法可以做到这一点,也许以某种方式使用事件 - 但对于我的情况,它工作得很好(特别是因为工作没有定期取消)。
除此之外 - 我100%同意Exceptions永远不应该用作流量控制工具..
@Kornel - 我对这篇文章有两个字......神圣的$ hit =)
这是一个简单的伪代码示例:
Class Job
{
Public Run(param1,param2,etc...)
{
Try
{
Log("Doing Something")
DoSomething()
Log("Doing Another")
DoAnother()
Log("This keeps going, etc, inside of these function we make the same Log calls where it makes sense")
Etc()
}
Catch(JobCancelledException)
{
status="Cancelled"
}
}
Private Log(ByVal str As String)
{
MessateToUser(str)
if(hasCancelled)
throw new JobCancelledException
}
private SomeEvent_WhenUserPushesCancelButton()
{
hasCancelled=True
}
}
答案 3 :(得分:1)
如果抛出异常,异常只会很昂贵。我确信设置一个Try..Catch块有一些非常小的成本,但它远远超过了根本没有捕获异常并导致程序崩溃的成本。正如其他人所指出的那样,Try..Catch块只应用于特殊情况。
答案 4 :(得分:1)
try块的开销非常低,因此如果没有抛出异常,那么应该没有明显的惩罚。抛出异常时发生的主要开销是发生寻找处理程序的堆栈遍历 - 因为你将异常缓存到如此接近源,我怀疑会有很多性能问题。理想情况下,您可以事先正确验证输入,但电子邮件验证相当复杂,因此在这种情况下可能不值得。
答案 5 :(得分:1)
如果抛出异常,它的成本很高,但这不是将异常用作正常流控制的借口。
如果您可以预先验证某些内容以避免首先发生异常,那么请执行此操作。例如。而不是你发布的内容,这样的事情会更好:
string invalidAddress = "notvalid@@@@@@lolzors.bomb";
return MailAddressValidator.IsValid(invalidAddress ); // doesn't cause exception
规则的例外情况是,您必须滚动自己版本的复杂方法(例如,在基类库中找到的没有TryParse
方法的东西),以避免异常在宏观方案中,无所谓。
如果您不确定,请使用代表性数据进行配置。如果用户每隔一秒在客户端应用程序表单中输入数据,则无关紧要。但是,如果它是用于处理可能来自任何地方的数千个电子邮件地址的服务,那么您应该确定您的假设。
答案 6 :(得分:0)
try..catch
块用作程序流控制的工具。
如果您不相信,请阅读this thread。
答案 7 :(得分:0)
通常,现代编译器仅对try
块施加最小成本,除非抛出异常。它们仍然不应该用于程序流控制,因为它们不像标准流程结构那样明显。异常基本上等同于COME FROM
语句。
答案 8 :(得分:0)
虽然你永远不应该使用try..catch进行程序流控制,但我不知道任何性能问题如果代码中没有实际抛出异常
答案 9 :(得分:0)
这是依赖于语言的,但据我所知,如果没有抛出异常,那么try
/ catch
就没有性能成本。
因此,在您使用预先验证的电子邮件地址的示例中,您所拥有的内容很好。