语法将从语言变为语言,但这是一个普遍的问题。
这有什么区别....
1 2 3 4 5 6 7 8 9 10 11 12 13
| try
{
Console .WriteLine("Executing the try statement.");
throw new NullReferenceException ();
}
catch (NullReferenceException e )
{
Console .WriteLine("{0} Caught exception #1.", e );
}
finally
{
Console .WriteLine("Executing finally block.");
} |
还有这个....
1 2 3 4 5 6 7 8 9 10
| try
{
Console .WriteLine("Executing the try statement.");
throw new NullReferenceException ();
}
catch (NullReferenceException e )
{
Console .WriteLine("{0} Caught exception #1.", e );
}
Console .WriteLine("Executing finally block."); |
我一直看到它被使用,所以我认为有一个很好的理由最终使用,但我无法弄清楚它是如何只是在语句之后放置代码,因为它仍然会运行。
有没有一个场景最终没有运行?
-
可能重复的尝试抓住最后的问题
-
..which可能是stackoverflow.com/questions/3216046/&hellip的副本; 这可能是stackoverflow.com/questions/345091/…的副本,它对这个问题有最好的答案。 好吧,一个好的,甜蜜的& 简短的一个。
在你的例子中,它并没有产生很大的不同。
想象一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| try
{
Console .WriteLine("Executing the try statement.");
throw new NullReferenceException ();
}
catch (SomeOtherException e )
{
Console .WriteLine("{0} Caught exception #1.", e );
}
finally
{
Console .WriteLine("Executing finally block.");
}
Console .WriteLine("Executing stuff after try/catch/finally."); |
在这种情况下,catch将不会捕获错误,因此永远不会达到整个try / catch / finally之后的任何内容。但是,finally块仍将运行。
-
啊,这很有道理。谢谢。
-
有趣的是,我从未见过它与throw一起使用。我想这只是一个好习惯。
-
@Maxx:更多的是处理最终导致未考虑的异常的情况。无论你如何退出try / catch,finally都将最终运行,即使这是由于您不知道可能发生的错误。所以这是放置清理代码等的更好的地方。
-
或者当没有捕获块时。然后,如果try块中的任何代码抛出错误,则异常将在堆栈中向上传播到调用例程,在堆栈的某处处理,或作为未处理的Exception处理。但是finally块中的代码仍然会运行。
-
或者在仅进行一些错误清理后重新抛出异常时。或者基本上任何其他时间你可以通过例外离开块。在这些情况下,块之后的代码将不会运行。这就是finally进来的地方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| try
{
throw new Exception ("Error!");
}
catch (Exception ex )
{
throw new Exception (ex, "Rethrowing!");
}
finally
{
// Will still run even through the catch kicked us out of the procedure
}
Console .WriteLine("Doesn't execute anymore because catch threw exception"); |
这实际上取决于 - 其他一些答案有很好的理由使用Finally块。但我认为最好的理由是因为你正在进行异常处理。您在Finally块中执行的操作通常涉及清理资源以确保正确继续,无论是否抛出异常 - 对我来说仍然是异常处理的一部分,至少是"尝试某事"操作的一部分。
恕我直言Finally范围强调了这样一个事实,即它的代码包含在异常情况下值得特别注意的东西。
最后阻止被保证被罚款。
因此,在您的示例中,两种情况的结果看起来都相同。
但如果你在catch块中使用return或throw,你可以看到有什么区别。
最后应该用于需要完成的所有事情,以保持系统的一致性。这通常意味着释放资源
无论抛出什么异常,最终都会被执行。在以下情况下,它应该用于释放资源:
-
完成连接
-
关闭文件处理程序
-
免费记忆
-
关闭数据库连接
让我举一个完整的例子。想象一下,您正在通过网络发送消息。在伪代码中:
1 2 3 4 5 6 7 8
| // With finally | //Without finally
try{ | try{
send_message() | send_message()
} catch(NetworkError){ | } catch(NetworkError){
deal_with_exception() | deal_with_exception()
} finally { | }
finalizes_connection() | finalizes_connection()
} | |
两个代码的唯一区别是当try块中保持的内容引发不是NetworkError的异常时,例如MethodNotFound。在第一种情况下,方法finalizes_connection()将被调用,而在第二种情况下,它将不会被调用。
通过多个程序自然地建立连接。那么在其他程序出现MethodNotFound异常的情况下会发生什么?在第一种情况下,您的程序将完成连接和其他程序,它会很高兴。在第二种情况下,另一个程序可以永远等待您的响应。如果其他程序每次只能接收一个连接怎么办?你刚刚窃听了另一个程序。
这也适用于您打开的文件,而其他程序无法打开以供阅读(在Windows中)。而对于内存,它永远不会被释放,现在你有内存泄漏。
终于总是运行。终于就像捕手一样从不错过任何东西。在你提到的例子中,是的,最后不会添加任何值。但最后通常用于处置/释放资源。
我不知道C#,但Java-ish语言中Finally块的目的是确保放弃系统资源,尤其是在垃圾收集不规则的情况下。这对所有人来说都是一样的原则。考虑块
1 2 3
| InputStream is = new FileInputStream ("foo.txt");
OutputStream os = new FileOutputStream ("D:/nonexistent/directory/bar.txt");
// Throws a FileNotFoundException. |
变量is已成功创建,并占用系统资源。进程一次只能使用固定数量的文件句柄。永远不会创建变量os,并抛出异常,并向呼叫者冒泡。在此过程中,is超出范围,并有资格进行垃圾回收。
但是,垃圾收集永远不会发生,或者它们可能会在未来的某个无限期发生。因此,is占用的系统资源可能永远不会被释放。这可能是昂贵的,或者如果程序发生足够的时间可能会使程序崩溃。因此,Finally块被放入Java中。其他语言也有类似的结构。在C ++中,确定性地调用析构函数。 LISPy语言有unwind-protect,但这些语言通常打包在with-foo宏中。
在Java 6及更低版本中,人们可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| try {
is = new FileInputStream ("foo.txt");
os = new FileOutputStream ("D:/nonexistent/directory/bar.txt");
// work...
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignored ) {}
}
if (os != null) {
try {
os .close();
} catch (IOException ignored ) {}
}
} |
你不能只调用is.close(),因为它可能会抛出,然后os永远不会被关闭。您还必须检查null。 Sane人使用Jakarta Commons-IO的IOUtils.closeQuietly()方法来替换块:
1 2 3 4
| } finally {
IOUtils .closeQuietly(is);
IOUtils .closeQuietly(os );
} |
但Java 7引入了更好的解决方案:尝试使用资源。 C#4可能首先出现类似的东西,微软的速度比Snoracle更快。
1 2 3 4 5 6
| try (
is = new FileInputStream ("foo.txt"),
os = new FileOutputStream ("D:/nonexistent/directory/bar.txt")
) {
// work...
} |
-
C#有using,它与IDisposable的实现大致相同(.net中的接口表示包含除RAM之外的本机资源的类)。 using (var r = new SomeNativeResource()) { /* do stuff with r; */ }几乎转换为var r = new SomeNativeResource(); try { /* do stuff with r; */ } finally { if (r != null) r.Dispose(); }。自从... 1.1或更早以来一直存在?... MSDN至少为VS 2003提供了一个页面。
-
原来的帖子被称为通用的。我想你需要在C#中使用Finally块,如果你必须做的事情你不能转换为IDisposable。这可能很少见。
-
是的...... C#中的finally块并不像Java中那么常见。 using涵盖了80%的用例。
最后使用它来处理程序崩溃是一个很好的做法。最终将永远运行。如果函数退出try catch块内部,或者在try或catch中抛出另一个错误,则finally仍将执行。您不会使用finally语句获得该功能。
try块需要至少一个catch或者finally.after执行所有catch块后,finally块将被执行。你可以添加你需要的任何逻辑,最终应该完成。
最后运行try和catch。它确保它将运行,但它不是100%保证它会[某些错误停止执行代码]
-
是的,但声明后的任何代码也是如此,对吧?
-
但是这不是简单地将它放在try-catch块之外的情况吗?
-
很多时候catch会重新抛出一个错误或者停止执行,在这种情况下,finally中的代码仍会运行,但try catch块之后的代码却不会。