12

我想知道以下两个 swnippest 在语义上是否相同,如果不是,有什么区别(我们假设我们要计算 R 类型的结果,并且要防止在执行过程中可能抛出的异常 X所以):

public R tcf(....) {
   try {
       R some = ...;
       ... compute the result ....
       return some; 
   }
   catch (X exception) {
       ... exception handling ....
   }
   finally {
       ... clean up ....
   }
}

以及以下内容:

public R tc(....) {
   try {
       R some = ...;
       ... compute the result ....
       return some; 
   }
   catch (X exception) {
       ... exception handling ....
   }
}

public R tf(....) {
    try {
        return tc(....);  // wrap the try-catch in tc()
    }
    finally {
        ... clean up ....
    }
 }

据我所见,它归结为如果包装在 try 块中的 try-catch 块与 finally 在语义上与 try-catch-finally 块相同,假设 finally 和 catch 短语中的代码保持不变同样,外部 try 块只是提升内部块的结果。

实际相关性:给定一个不使用 try-catch-finally 的代码库,什么时候应该使用,并且由于某种原因,人们无法触及该代码,因此可以或多或少地机械地生成一层包装方法,以添加最后。

我完全了解这样一个事实,即出于多种原因,应该尽可能使用 try ... catch ... finally。具体来说,我建议以任何方式重构第一个示例,使其看起来像第二个示例。

相反,我想确保示例 2 可以安全地重构为示例 1。

4

5 回答 5

15

在功能上,它们是等价的。

我认为以分配相关资源的相同方法执行清理是一种很好的方式。在某些情况下,这是处理事情的唯一实用方法(例如,如果清理涉及tcf/的本地变量tc)。

此外,如果tc不自行清理,清理将成为函数合同的一部分,作为调用者的义务。这使得设计更容易出错,因为清理很容易忘记或出错。此外,如果清理中涉及的步骤发生任何变化,则需要跟踪和更新每个调用者。

底线:如果可以在 中执行清理tcf,那么应该可以。

于 2013-01-24T09:08:22.137 回答
3

然而,它们是相同的。try/finally 应该总是在请求追索权(最终释放)之后。(请注意,这发生在尝试之前)

例如:

   getLock();
   try {
       doSomething()
   }
   finally {
       releaseLock();
   }

因为很容易忘记清理,所以它应该总是发生在与获取资源相同的位置。这样做的原因是,您永远不应该让呼叫者承担他们必须做的事情(您可以自己做)

于 2013-01-24T09:09:31.377 回答
2

没有在与 try/catch 相同的方法中执行 finally 会使您对执行 try/catch 的方法在某个点被调用而不执行 finally,这可能是一个错误。
因此,我不建议您这样写,尽管在您描述的场景中,当包含 try/catch 的方法无法修改时,必须通过 finally 添加功能,这是唯一的方法。

于 2013-01-24T09:12:04.487 回答
2

我认为您的描述非常准确,因为tf finally将在两种情况下都执行,并且异常处理将在任一tcftf catch块中处理。

也就是说,在示例(1)中:如果您的 中发生异常try,流程将执行您的catch块,然后执行您的finally block. 在示例(2)中tc,如果您的块中发生异常try,则流程将在您的catch块中继续,然后(假设未重新抛出异常)返回到调用行 in tf。完成您的tf try区块后,流程将在您的tf finally区块中继续。

我想要注意的主要含义是:您可能无法按照您建议的方式进行纠正:

  1. 如果您在第二个示例中实现您的代码,您将不一定能够访问tc资源tf来清理它们。
  2. 即使可以,您也在一个不接近资源使用的层清理资源,甚至可能不被框架的其他客户端代码使用。我想这是文档和培训的问题。
于 2013-01-24T09:15:30.797 回答
1

两者是相同的。但 finally 用于当您有中断函数之间的风险或想要释放函数持有的一些资源时。在这种情况下,catch 会被跳过,但最终肯定会执行。

try 可以与 catch 或 finally 或两者一起使用。finally 一般不能显示发生的异常,但 catch 可以跟踪异常。

于 2013-01-24T09:13:36.023 回答