Exception handling try-catch/except-finally语句中finally的意义是什么
多年来,我在许多语言中使用了try-catch/except-finally变体,今天有人问我finally的意义是什么,我无法回答 基本上,你为什么要把一个语句放在最后,而不是放在整个try-catch块之后?或者换句话说,以下代码块之间是否存在差异:Exception handling try-catch/except-finally语句中finally的意义是什么,exception-handling,finally,Exception Handling,Finally,多年来,我在许多语言中使用了try-catch/except-finally变体,今天有人问我finally的意义是什么,我无法回答 基本上,你为什么要把一个语句放在最后,而不是放在整个try-catch块之后?或者换句话说,以下代码块之间是否存在差异: try{ //a} catch {//b} finally {//c} try{//a} catch{//b} //c 编辑: 各位,我知道最终会做什么,我已经使用它很多年了,但我的问题是在上面的示例中,将/c放入最终似乎是多余的,不是吗
try{ //a}
catch {//b}
finally {//c}
try{//a}
catch{//b}
//c
编辑:各位,我知道最终会做什么,我已经使用它很多年了,但我的问题是在上面的示例中,将
/c
放入最终似乎是多余的,不是吗?最后
确保即使出现异常,也执行您的代码
finally块用于清理try块中分配的任何资源,以及运行即使出现异常也必须执行的任何代码
即使try块中抛出异常,也会执行Finally块。因此,例如,如果您以前打开过一个流,您可能希望关闭该流,或者抛出异常,或者不抛出异常。Finally块对于此类问题非常有用。Finally块的目的是确保代码在三种情况下运行,这三种情况单独使用“catch”块不会非常干净地处理:
try
块中的代码通过return退出
如果catch
块中的代码重新调用捕获的异常,或者(意外地或有意地)最终抛出一个新异常。
如果try
块中的代码遇到异常,try
没有catch
。
人们可以在每次返回或抛出之前复制finally
代码,并将catch
块包装在自己的try/catch中,以允许意外异常发生的可能性,但放弃所有这些,只需使用finally
块就容易多了
顺便说一句,我希望语言设计人员能够包括一个异常
参数到finally
块,以处理在异常发生后需要清理,但仍然希望它渗透调用堆栈的情况(例如,可以将构造函数的代码包装在这样的构造中,如果构造函数将异常退出,则处理正在构造的对象)试试看
让我们看看没有的标准情况最后
:
void myFunction() {
var r = allocateResources();
r.doSomething();
if(somethingBadHappens) {
freeResources(r);
throw new Exception(CODE42);
}
r.doSomethingMore();
freeResources(r);
}
在上面的代码段中,您重复了freeResources()
:这可能是多条需要重复的语句。这是一种气味,最后
块是干净代码的解决方案:
void myFunction() {
var r = allocateResources();
try {
r.doSomething();
if(somethingBadHappens) throw new Exception(CODE42);
r.doSomethingMore();
}
finally {
freeResources(r);
}
happyFunction();
}
让我们实现三个抽象级别:
- A1是提供
allocateResources()
函数的库代码
- A2是我们的代码提供的
myFunction
,消费A1
- A3是某个客户端代码在try-catch块中使用
myFunction
:
现在让我们看看会发生什么:
- 如果
allocateResources()
抛出A1,我们不知道如何在A2中处理它(A2代码可以在无控制台的环境中运行),因此我们将情况延迟到A3,而不添加任何其他代码。如果在此处引发异常,则不会执行finally块,因为finally
绑定到未输入的try
- 如果在try块中发生
somethingbad
,堆栈将展开到A3,在A3中处理情况,但在执行最后块之前,因此如果没有异常发生,我们不需要重复它
- 在
最后
之前,我们可以添加catch
块,并尝试解决A1中的一些潜在异常,这些异常可能出现在调用r.doSomething
方法中。通常我们希望尽快处理异常,以使客户端代码(A3)更适合客户端编码人员
happyFunction()
只有在myFunction()
中没有抛出任何内容时才会执行(在try
块的内部或外部)
正如@supercat所指出的,如果try
块通过return退出,那么finally
块也会执行。我建议您避免这种坏习惯,每个函数只有一个return(可能在函数的最开始就存在一些早期返回)。使用单返回函数的原因如下:
代码更具可读性:您可以查看结尾并查看函数返回的内容。在多次返回中,您必须找到所有返回事件,检查所有ifs,思考ifs满足的时间,然后才知道函数返回的内容
编译器可以优化代码,请参阅
多重返回的原因是避免了许多嵌套的ifs,但还有其他技术可以解决它。异常
s在此规则中是异常。但是我提到的两个代码块之间的区别是什么?在这两种情况下都执行了//c
,对吗?请查看编辑后的问题。@Ali-finally块允许您如果您不在本地处理,请清理分配的所有资源,并允许expetion对调用堆栈进行propogate备份。在第二个版本中,如果//a中的代码调用“return”退出函数,则不会执行//c。最后确保调用//c,即使函数提前退出……也不会回答实际问题我们试过了,你抓住了,我们终于找到了这个问题的答案!我认为这里的关键是,即使有返回
function A3code() {
try {
myFunction();
doSomething();
}
catch(Exception e) {
// no hanging resources here
Console.WriteLine(e);
}
}