最后在try catch / finally语句中有什么意义

时间:2012-03-13 16:16:34

标签: exception-handling finally

我已经使用了多种语言的try-catch / except-finally变种多年,今天有人问我最后的意思是什么,我无法回答。

基本上你为什么要在finally中放入一个语句而不是仅仅将它放在整个try-catch块之后?或者换句话说,以下代码块之间存在差异:

try{ //a}
catch {//b}
finally {//c}


try{//a}
catch{//b}
//c

编辑:
人们,我知道最后会做什么,我已经使用了很长时间,但我的问题是在上面的例子中,将//c放在最后似乎是多余的,不是吗?

4 个答案:

答案 0 :(得分:82)

finally块的目的是确保代码在三种情况下运行,而这些情况不会仅仅使用“catch”块来处理:

  1. 如果`try`块中的代码通过`return`退出
  2. 如果catch块中的代码重新捕获捕获的异常,或者 - 意外或故意 - 最终会抛出一个新异常。
  3. 如果`try`块中的代码遇到没有catch的异常。

可以在finally之前复制return代码或抛出,并在自己的try / catch中包装catch块以允许发生意外异常的可能性,但它是更容易放弃所有这些,只需使用finally块。

顺便说一句,我希望语言设计者将包含的一个问题是exception块的finally参数,以处理在异常后需要清理但仍希望它的情况渗透调用堆栈(例如,可以在这样的构造中包装构造函数的代码,并且Dispose正在构造的对象(如果构造函数将以异常退出)。

答案 1 :(得分:2)

即使在try块中抛出异常,也会执行最后一个块。因此,例如,如果您之前打开了一个流,则可能需要关闭该流,否则抛出异常。最后块对于这样的问题很有用。

答案 2 :(得分:0)

Finally即使您遇到异常,也要确保您的代码已执行。

finally块对于清理try块中分配的任何资源以及运行任何必须执行的代码(即使存在异常)非常有用

http://msdn.microsoft.com/en-us/library/zwc8s4fz(v=vs.80).aspx

答案 3 :(得分:0)

finally是一种语法糖,允许以try-catch模式使用DRY原理。如果库代码没有足够的信息来处理某些状态,并且希望客户端代码解决它,通常会引发异常。如果没有库与客户端的代码分离,则可以使用if而不是try处理所有内容。

让我们看看没有finally的标准情况:

void myFunction() {
  var r = allocateResources();
  r.doSomething();
  if(somethingBadHappens) {
    freeResources(r);
    throw new Exception(CODE42);
  }
  r.doSomethingMore();
  freeResources(r);
}

在上面的代码段中,您重复freeResources():这可以是您需要重复的多个语句。这闻起来很香,finally块是干净代码的解决方案:

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 是一些在尝试捕获块中消耗myFunction的客户端代码:
function A3code() {
  try {
    myFunction();
    doSomething();
  }
  catch(Exception e) {
    // no hanging resources here
    Console.WriteLine(e);
  }
}

现在让我们看看会发生什么:

  • 如果allocateResources()抛出A1,我们不知道如何在A2中处理它(A2代码可以在没有控制台的环境中运行),因此我们将情况推迟到A3,而无需添加任何其他代码。 如果在此处引发Exception,则不会执行finally块,因为finally已绑定到未输入的try
  • 如果somethingBadHappens在try块中,则堆栈会退回到A3,并在执行finally块之前先处理情况但是,因此我们无需重复如果没有例外发生的话。
  • finally之前,我们可以添加catch块,并尝试解决A1的一些潜在异常,这些异常可能在调用r.doSomething方法中出现。通常,我们希望尽快处理异常,以使客户端代码(A3)对于客户端编码人员而言更为舒适。
  • happyFunction()仅在myFunction()中(try块的内部或外部)没有抛出任何异常时执行。

正如@supercat指出的那样,如果finally块通过return退出,则try块也会执行。我建议您避免这种不良习惯,并且在每个函数中只有一个返回值(也许在函数的开始处就存在一些早期)。单次返回功能的原因是:

  1. 代码更具可读性:您先看最后,看看函数返回的内容。在多次返回中,您必须找到所有返回事件,检查所有if,考虑何时满足if,然后才知道函数返回什么。
  2. 编译器可以优化代码,请参见copy elision

多次返回的原因是避免了许多嵌套的if,但是还有其他解决方法。 Exception是此规则的例外。