35

除了语法,有什么区别

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

try {
}
catch() {
}

x = 3;

编辑:在.NET 2.0 中?


所以

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

在行为上是等价的吗?

4

16 回答 16

44

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

于 2008-09-08T20:43:44.000 回答
36

取决于语言,因为可能存在一些细微的语义差异,但想法是它会(几乎)始终执行,即使 try 块中的代码抛出异常也是如此。

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

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

于 2008-09-08T20:43:21.817 回答
10

在 Java 中:

finally 总是被调用,不管异常是否在 catch() 中被正确捕获,或者事实上你是否有一个 catch。

于 2008-09-08T20:42:54.220 回答
9

try catch finally是非常重要的构造。可以肯定的是,即使抛出异常,finally块中的代码也会被执行。处理外部资源以释放它们非常重要。垃圾收集不会为您做到这一点。在 finally 部分中,您不应该有return语句或抛出异常。这样做是可能的,但这是一种不好的做法,可能会导致不可预知的结果。

如果你试试这个例子:

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

结果将是 2:)

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

于 2008-09-08T21:04:01.720 回答
6

有几件事使 finally 块有用:

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

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

于 2008-09-08T21:11:15.367 回答
3

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

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

通常,finally 用于在您自己之后进行清理(关闭 DB-connections、File-Handles 等)。

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

于 2008-09-08T20:44:17.180 回答
1

即使抛出异常或到达 return 语句(尽管这可能取决于语言),也会始终调用 finally 块(实际上并非总是...)。这是一种清理方法,你知道它总是会被调用。

于 2008-09-08T20:46:31.217 回答
1

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{} 之外的任何内容,第二个有效地返回),但总是干净整洁。

于 2008-09-08T21:10:33.887 回答
1

@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();  
}
于 2008-09-09T16:05:45.703 回答
1

这不是回答,而是批评。这个问题很,但这一直困扰着我。我在这里找到它是有原因的。我已经阅读了每个答案,在我看来,没有人真正考虑过。

我真的认为 没有什么好处finally,这可能就是为什么它直到“最近”才出现在编程语言中。大多数说明的示例stream.close()都可能导致空引用异常,因此您仍然需要测试它是否为空。

是的,如果你从内部返回try{}finally仍然运行。但这是好的做法吗?好像是脑力体操,还不如带goto回来。为什么不等待,然后在阻塞后返回?所做finally {}的只是在代码中添加两三行。

于 2019-09-30T13:51:06.203 回答
0

因此,您可以清理在 try 块中初始化的任何打开的连接等。如果您打开一个连接,然后发生异常,则该异常将不会被正确关闭。这种类型的场景就是 finally 块的用途。

于 2008-09-08T20:42:32.097 回答
0

finally 块应该执行,无论您是否捕获了异常。参见Try / Catch / finally 示例

于 2008-09-08T20:44:04.903 回答
0

@Ed,您可能正在考虑像catch(...)在 C++ 中捕获未指定异常的东西。

但是finally无论catch块中发生什么,代码都会被执行。

Microsoft 在C# 的 try-finally上有一个帮助页面

于 2008-09-08T20:51:16.697 回答
0

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 里面的任何东西都不能保证运行。想象一下,您收到中止信号、窗口崩溃或断电。最终依赖于业务关键代码是不好的。

于 2008-09-08T20:57:43.373 回答
0

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

于 2008-09-08T20:59:45.567 回答
0

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

例如,关闭数据库会话或 JMS 连接,或释放某些操作系统资源。

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

于 2008-09-27T23:49:04.560 回答