撇开语法不谈,两者有什么区别

try {
}
catch() {
}
finally {
    x = 3;
}

try {
}
catch() {
}

x = 3;

编辑:在.NET 2.0 中?


所以

try {
    throw something maybe
    x = 3
}
catch (...) {
    x = 3
}

行为上是等价的吗?

有帮助吗?

解决方案

取决于语言,因为可能存在一些轻微的语义差异,但想法是它会(几乎)总是执行,即使 try 块中的代码引发异常。

在第二个示例中,如果 catch 块中的代码返回或退出,则 x = 3 将不会被执行。首先它会的。

在.NET平台中,在某些情况下不会执行finally块:安全异常、线程暂停、计算机关闭:)等。

其他提示

好吧,一方面,如果您在 try 块内返回,finally 仍然会运行,但 try-catch-finally 块下面列出的代码不会。

在爪哇中:

最后总是会被调用,无论异常是否在 catch() 中被正确捕获,或者实际上是否有 catch。

试着抓 最后 是非常重要的构造。可以确定的是,即使抛出异常,finally 块中的代码也会被执行。处理外部资源并释放它们非常重要。垃圾收集不会为你做到这一点。在最后一部分你不应该 返回 语句或抛出异常。这样做是可能的,但这是一种不好的做法,并且可能会导致不可预测的结果。

如果你尝试这个例子:

try {
  return 0;
} finally {
  return 2;
}

结果将是 2:)

与其他语言的比较: 从最后返回

有几个因素可以使finally块变得有用:

  1. 如果从 try 或 catch 块返回,则在控制权交还给调用函数之前,finally 块仍会执行
  2. 如果catch块中发生异常,或者try块中发生未捕获类型的异常,则finally块中的代码仍然会被执行。

这些使得finally块非常适合关闭文件句柄或套接字。

在 try 和 catch 为空的情况下,没有区别。否则你可以确定,finally 将会被执行。

例如,如果您在 catch 块中抛出一个新的异常(重新抛出),那么只有在finally 块中的赋值才会被执行。

通常,finally 用于在您自己之后进行清理(关闭数据库连接、文件句柄等)。

你不应该在finally中使用控制语句(return、break、 continue),因为这可能是维护的噩梦,因此被认为是不好的做法

finally 块将始终被调用(当然不是真的 总是 ...)即使抛出异常或到达返回语句(尽管这可能与语言相关)。这是一种您知道总会被调用的清理方法。

@iAn 和 @mats:

一般来说,我不会“拆除”finally{} 中在 try{} 中“设置”的任何内容。最好将流创建拉到 try {} 之外。如果您需要处理流创建上的异常,则可以在更大的范围内完成。

StreamReader stream = new StreamReader("foo.bar");  
try {
    mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally {
    stream.close();  
}

因此您可以清理任何打开的连接等。在 try 块中初始化。如果您打开连接然后发生异常,则该异常将无法正确关闭。这种情况就是finally 块的用途。

无论您是否捕获到异常,finally 块都应该执行。看 Try/Catch/Finally 示例

@艾德, ,你可能会想到类似的东西 catch(...) 捕获 C++ 中的非指定异常。

finally 是无论发生什么都会执行的代码 catch 块。

微软有一个帮助页面 C# 的 try-finally

finally 块与 try/catch 位于同一范围内,因此您可以访问其中定义的所有变量。

想象一下您有一个文件处理程序,这就是它的编写方式的差异。

try
{
   StreamReader stream = new StreamReader("foo.bar");
   stream.write("foo");
}
catch(Exception e) { } // ignore for now
finally
{
   stream.close();
}

相比

StreamReader stream = null;
try
{
    stream = new StreamReader("foo.bar");
    stream.write("foo");
} catch(Exception e) {} // ignore

if (stream != null)
    stream.close();

但请记住,最终内部的任何内容都不能保证运行。想象一下,您收到中止信号、窗口崩溃或断电。依赖于最终的业务关键代码是不好的。

即使发生未处理的异常,finally 中的任何代码也会运行。通常,finally 代码用于使用 .dispose() 清理非托管代码的本地声明。

作为开发人员,finally 块允许您自己进行清理,无论 try{} 块中的前面代码的操作是否遇到错误,并且其他人已经指出了这一点,这主要属于释放资源的范畴 - 关闭指针/套接字/结果集,返回到池的连接等。

@mats 是非常正确的,总是存在“硬”失败的可能性 - finally 块不应该包含关键任务代码,这些代码应该始终在 try{} 内以事务方式完成

@mats 再次 - 真正的美妙之处在于它允许您从自己的方法中抛出异常,并且仍然保证您清理干净:

try
{
StreamReader stream = new StreamReader("foo.bar");
mySendSomethingToStream(stream);
}
catch(noSomethingToSendException e) {
    //Swallow this    
    logger.error(e.getMessage());
}
catch(anotherTypeOfException e) {
    //More serious, throw this one back
    throw(e);
}
finally
{
stream.close();
}

因此,我们可以捕获多种类型的异常,以不同的方式处理它们(第一个允许执行 try{} 之外的任何内容,第二个有效返回),但总是干净利落地清除。

在 Java 中,您可以将它用于任何您想要执行的操作,无论您是否使用了“返回”、只是运行了 try 块,还是捕获了异常。

例如,关闭数据库会话或 JMS 连接,或取消分配某些操作系统资源。

我猜它在.NET 中是类似的?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top