我见过有人说,使用不带参数的catch是一种糟糕的形式,尤其是当catch什么都不做的时候:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

然而,这被认为是良好的形式:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

据我所知,将清理代码放在finally块和将清理代码放在try. catch块之后的唯一区别是,如果你在try块中有返回语句(在这种情况下,finally中的清理代码将运行,但try. catch块之后的代码将不会运行)。

否则,最后有什么特别的?


当前回答

因为当这一行引发异常时,你不会知道。

对于第一个代码块,异常将被简单地吸收,即使程序的状态可能是错误的,程序也将继续执行。

对于第二个块,将抛出异常并出现冒泡,但reader.Close()仍然保证运行。

如果不期望出现异常,那么就不要使用try. catch块,这样当程序进入糟糕的状态而你不知道原因时,就很难进行调试。

其他回答

使用Try…Catch . .最后,如果您的方法知道如何在本地处理异常。异常发生在Try中,在Catch中处理,然后在Finally中完成清理。

如果你的方法不知道如何处理异常,但需要在异常发生后进行清理,请使用Try..最后

通过这种方式,异常被传播到调用方法,如果调用方法中有任何合适的Catch语句,则进行处理。如果当前方法或任何调用方法中没有异常处理程序,则应用程序将崩溃。

最后,确保在将异常传播到调用方法之前完成了本地清理。

“Finally”是一个声明,“你必须总是做一些事情来确保程序状态正常”。因此,如果存在异常可能会抛出程序状态,那么拥有一个异常总是很好的形式。编译器还会竭尽全力确保Finally代码运行。

“Catch”是“我可以从这个异常中恢复”的声明。您应该只从真正可以纠正的异常中恢复—不带参数的catch表示“嘿,我可以从任何异常中恢复!”,这几乎总是不正确的。

如果有可能从每个异常中恢复,那么它就真的是语义上的吹毛求疵,关于你所声明的意图是什么。然而,事实并非如此,而且几乎可以肯定的是,在你上面的框架能够更好地处理某些异常。因此,使用finally,让您的清理代码免费运行,但仍然让更有知识的处理程序来处理问题。

只要不抛出异常,示例之间的有效差异就可以忽略不计。

但是,如果在'try'子句中抛出异常,则第一个示例将完全忽略它。第二个示例将向调用堆栈的下一个步骤抛出异常,因此所述示例的区别在于,一个示例完全掩盖了任何异常(第一个示例),而另一个示例(第二个示例)保留了异常信息,以便后续处理,同时仍然执行'finally'子句中的内容。

例如,如果您将代码放在第一个示例的'catch'子句中,该子句抛出异常(无论是最初引发的异常还是新抛出的异常),则阅读器清理代码永远不会执行。最后执行,不管'catch'子句中发生了什么。

因此,'catch'和'finally'之间的主要区别是,'finally'块的内容(少数例外)可以被认为是保证执行的,即使面对意外的异常,而'catch'子句之后的任何代码(但在'finally'子句之外)都不会带有这样的保证。

顺便说一句,Stream和StreamReader都实现了IDisposable,并且可以包装在一个“using”块中。'Using'块在语义上等同于try/finally(没有'catch'),所以你的例子可以更简洁地表达为:

using (StreamReader reader = new  StreamReader("myfile.txt"))
{
  int i = 5 / 0;
}

...它会在StreamReader实例超出作用域时关闭并销毁它。 希望这能有所帮助。

最大的区别是尝试…Catch将吞下异常,隐藏发生错误的事实。Try .finally将运行您的清理代码,然后异常将继续运行,由知道如何处理它的程序来处理。

try/catch块捕获所有异常的问题是,如果发生未知异常,您的程序现在处于不确定状态。这完全违背了快速失败规则——如果发生异常,您不希望程序继续运行。上面的try/catch甚至会捕获outofmemoryexception,但这绝对是程序不会在其中运行的状态。

Try/finally块允许您在快速失败的情况下执行清理代码。对于大多数情况,您只想在全局级别捕获所有异常,以便您可以记录它们,然后退出。