What is the difference between
try { }
catch
{ throw; }
和
try { }
catch(Exception e)
{ throw e;}
何时应该使用其中一种?
这些结构
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
try和catch在某些方面是相似的,因为两者都会捕获try块中抛出的每一个异常(除非你只是用它来记录异常,应该避免使用)。现在看看这些:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
第一和第二个try-catch块完全相同,它们只是重新抛出当前异常,该异常将保留其“源”和堆栈跟踪。
第三个try-catch块不同。当它抛出异常时,它将更改来源和堆栈跟踪,以便看起来异常已经从这个方法中抛出,从包含该try-catch块的方法中的那行throw e
抛出。
哪种应该使用?这实际上取决于每种情况。
假设你有一个名为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) { ... }
第一种方式保留了堆栈跟踪信息,而第二种方式重置了它。这意味着,如果您使用第二种方法,则异常的堆栈跟踪将始终从此方法开始,并且您将丢失原始异常跟踪信息,这对于阅读异常日志的人来说可能是灾难性的,因为他永远不会找到异常的根本原因。
当您想要向堆栈跟踪添加其他信息时,第二种方法可能是有用的,但它的使用方式如下:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
有一篇博客文章讨论了这些差异。
你应该使用
try { }
catch(Exception e)
{ throw }
如果你想在重新抛出异常之前对其进行某些操作(例如记录日志),可以使用孤独的throw语句来保留堆栈跟踪。
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);
}
catch(Exception e)
部分。而且那与throw
和throw e
是分开的。 - H H