除了语法,有什么区别
try {
}
catch() {
}
finally {
x = 3;
}
和
try {
}
catch() {
}
x = 3;
编辑:在.NET 2.0 中?
所以
try {
throw something maybe
x = 3
}
catch (...) {
x = 3
}
在行为上是等价的吗?
除了语法,有什么区别
try {
}
catch() {
}
finally {
x = 3;
}
和
try {
}
catch() {
}
x = 3;
编辑:在.NET 2.0 中?
所以
try {
throw something maybe
x = 3
}
catch (...) {
x = 3
}
在行为上是等价的吗?
好吧,一方面,如果你在 try 块中返回,finally 仍然会运行,但 try-catch-finally 块下面列出的代码不会。
取决于语言,因为可能存在一些细微的语义差异,但想法是它会(几乎)始终执行,即使 try 块中的代码抛出异常也是如此。
在第二个例子中,如果 catch 块中的代码返回或退出,x = 3 将不会被执行。首先它会。
在 .NET 平台中,在某些情况下,finally 块的执行不会发生:安全异常、线程暂停、计算机关闭 :) 等。
在 Java 中:
finally 总是被调用,不管异常是否在 catch() 中被正确捕获,或者事实上你是否有一个 catch。
try catch finally是非常重要的构造。可以肯定的是,即使抛出异常,finally块中的代码也会被执行。处理外部资源以释放它们非常重要。垃圾收集不会为您做到这一点。在 finally 部分中,您不应该有return语句或抛出异常。这样做是可能的,但这是一种不好的做法,可能会导致不可预知的结果。
如果你试试这个例子:
try {
return 0;
} finally {
return 2;
}
结果将是 2:)
与其他语言的比较:从最终返回
有几件事使 finally 块有用:
这些使 finally 块非常适合关闭文件句柄或套接字。
在 try 和 catch 为空的情况下,没有区别。否则,您可以确定 finally 将被执行。
例如,如果你在你的 catchblock 中抛出一个新的异常(重新抛出),那么只有在 finally 块中的赋值才会被执行。
通常,finally 用于在您自己之后进行清理(关闭 DB-connections、File-Handles 等)。
你不应该在 finally 中使用控制语句(return、break、continue),因为这可能是维护的噩梦,因此被认为是不好的做法
即使抛出异常或到达 return 语句(尽管这可能取决于语言),也会始终调用 finally 块(实际上并非总是...)。这是一种清理方法,你知道它总是会被调用。
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{} 之外的任何内容,第二个有效地返回),但总是干净整洁。
@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();
}
这不是回答,而是批评。这个问题很老,但这一直困扰着我。我在这里找到它是有原因的。我已经阅读了每个答案,在我看来,没有人真正考虑过。
我真的认为 没有什么好处finally
,这可能就是为什么它直到“最近”才出现在编程语言中。大多数说明的示例stream.close()
都可能导致空引用异常,因此您仍然需要测试它是否为空。
是的,如果你从内部返回try{}
,finally
仍然运行。但这是好的做法吗?好像是脑力体操,还不如带goto
回来。为什么不等待,然后在阻塞后返回?所做finally {}
的只是在代码中添加两三行。
因此,您可以清理在 try 块中初始化的任何打开的连接等。如果您打开一个连接,然后发生异常,则该异常将不会被正确关闭。这种类型的场景就是 finally 块的用途。
finally 块应该执行,无论您是否捕获了异常。参见Try / Catch / finally 示例
@Ed,您可能正在考虑像catch(...)
在 C++ 中捕获未指定异常的东西。
但是finally
无论catch
块中发生什么,代码都会被执行。
Microsoft 在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 中的任何代码也会运行。通常,finally 代码用于使用 .dispose() 清理非托管代码的本地声明。
在 Java 中,无论您是使用“返回”、只是运行 try 块还是捕获了异常,您都可以将它用于您想要执行的任何事情。
例如,关闭数据库会话或 JMS 连接,或释放某些操作系统资源。
我猜它在.NET中是相似的?