try / catch / throw和try / catch(e)/ throw e之间的区别


103

之间有什么区别

try { }
catch
{ throw; }

try { }
catch(Exception e)
{ throw e;}

我什么时候应该使用另一个?

Answers:


151

建筑

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }

两者相似,因为两者都将捕获块中抛出的每个异常try(并且,除非您只是使用它来记录异常,否则应避免)。现在看这些:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}

第一个try-catch块和第二个try-catch块完全相同,它们只是重新抛出当前异常,而该异常将保留其“源”和堆栈跟踪。

第三个try-catch块是不同的。当它引发异常时,它将更改源和堆栈跟踪,以便看起来已从此方法引发异常,从throw e包含try-catch块的方法的那一行开始。

您应该使用哪一个?这实际上取决于每种情况。

假设您有一个Person带有.Save()将其持久化到数据库中的方法的类。假设您的应用程序在Person.Save()某处执行该方法。如果您的数据库拒绝保存Person,.Save()则将引发异常。您应该使用throw还是throw e在这种情况下?这要看情况。

我更喜欢做的是:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}

这应该将DBException作为正在抛出的较新异常的“内部异常”。因此,当您检查此InvalidPersonException时,堆栈跟踪将包含返回Save方法的信息(这可能足以解决问题),但是如果需要,您仍然可以访问原始异常。

最后一点,当您期望一个异常时,您应该确实捕获该特定的异常,而不是一般的异常Exception,即,如果您期望一个InvalidPersonException,则您应该首选:

try { ... }
catch (InvalidPersonException e) { ... }

try { ... }
catch (Exception e) { ... }

祝好运!


34

第一个保留堆栈跟踪,第二个重置堆栈跟踪。这意味着,如果您使用第二种方法,则异常的堆栈跟踪将始终从该方法开始,并且您将丢失原始的异常跟踪,这对于读取异常日志的人可能是灾难性的,因为他将永远找不到异常的原始原因。 。

当您想向堆栈跟踪中添加其他信息时,第二种方法可能会很有用,但它的用法如下:

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}

有一篇博客文章讨论了差异。


嗯,这是个很棒的东西!
Myles

那么为什么要使用第二个呢?仅使用第一个更好吗?
卡里姆

1
当您需要检查特定的例外情况时,第二个便派上用场-想到OutOfRangeException-或需要记录消息等。第一个似乎是类似于try {} catch(...){}的通配符异常处理程序。在C ++中。
3Dave

1
David,仅适用于catch (Exception e)部分。这throw与vs 分开throw e
汉克·霍尔特曼

6

你应该用

try { }
catch(Exception e)
{ throw }

如果您想在抛出异常之前做一些例外处理(例如记录)。孤独的抛出保留了堆栈跟踪。


如果我将“ throw”替换为“ throw e”,将会发生什么?
卡里姆

5

无参数catch和a之间的区别在于catch(Exception e)您可以引用该异常。从框架版本2开始,非托管异常被包装在托管异常中,因此无参数异常对于任何事物都不再有用。

throw;和之间的区别throw e;是,第一个用于引发异常,第二个用于引发新创建的异常。如果使用第二个异常重新抛出异常,它将把它当作新异常对待,并替换最初抛出该异常的所有堆栈信息。

因此,您不要在问题中使用任何一种替代方法。您不应该使用无参数捕获,而应该使用它throw;来抛出异常。

同样,在大多数情况下,对于所有异常,应使用比基类更具体的异常类。您应该只捕获预期的异常。

try {
   ...
} catch (IOException e) {
   ...
   throw;
}

如果要在引发异常时添加任何信息,请创建一个新异常,并将原始异常作为内部异常保留所有信息:

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.