12

次の 2 つの 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 ....
    }
 }

私の知る限り、finally と catch フレーズのコードがそのままであると仮定すると、try ブロックでラップされた try-catch ブロックが finally で try-catch-finally ブロックと意味的に同じであるかどうかに要約されます。同じで、外側の try ブロックは内側のブロックの結果を昇格させるだけです。

実用的な関連性: try-catch-finally を使用しないコード ベースがあり、使用すべきときに、何らかの理由でそのコードにアクセスできない場合、追加するラッパー メソッドのレイヤーを多かれ少なかれ機械的に生成することができます。最後に。

多くの理由から、可能な限り try ... catch ... finally を使用する必要があるという事実を十分に認識しています。具体的には、最初の例を 2 番目の例のようにリファクタリングするように提案しているわけではありません。

むしろ、例 2 を安全に例 1 にリファクタリングできるようにしたいと考えています。

4

5 に答える 5

15

機能的には、それらは同等です。

問題のリソースを割り当てたのと同じ方法でクリーンアップを実行するのが良いスタイルだと思います。場合によっては、これが物事を実行するための唯一の実用的な方法です(たとえば、クリーンアップにtcf/にローカルな変数が含まれる場合tc)。

また、tcそれ自体がクリーンアップされない場合、クリーンアップは、呼び出し元の義務として、関数のコントラクトの一部になります。これにより、クリーンアップを忘れたり間違えたりしやすいため、設計でエラーが発生しやすくなります。さらに、クリーンアップに関連する手順が何らかの形で変更された場合、すべての発信者を追跡して更新する必要があります。

結論:でクリーンアップを実行できる場合は、実行tcfする必要があります。

于 2013-01-24T09:08:22.137 に答える
3

ただし、それらは同じです。try/finally は、recourse (最終的に解放される) が要求された直後に常にある必要があります。(これは試行の直前に発生することに注意してください)

例えば:

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

後始末は本当に忘れがちなので、常にリソースの取得と同じ場所で行う必要があります。その理由は、発信者が常にしなければならないことで発信者に負担をかけてはならないからです (そして、自分で行うこともできます)。

于 2013-01-24T09:09:31.377 に答える
2

try/catch と同じメソッドで finally を実行しないと、finally が実行されずに、ある時点で try/catch を実行するメソッドが呼び出される可能性があります。これはバグである可能性があります。
したがって、そのように書くことはお勧めしませんが、あなたが説明したシナリオでは、try/catch を含むメソッドを変更できないときに finally を介して機能を追加する必要がありますが、それが唯一の方法です。

于 2013-01-24T09:12:04.487 に答える
2

tf finallyどちらの場合でも実行され、例外処理はどちらかtcfまたはtf catchブロックで処理されるという点で、あなたの説明はかなり正確だと思います。

つまり、例 (1): で例外が発生した場合try、フローはcatchブロックを実行し、その後にfinally block. の例 (2) では、ブロックでtc例外が発生した場合try、フローはブロックで続行され、catch(例外が再スローされないと仮定して) の呼び出し行に戻りtfます。ブロックが完了すると、tf tryブロック内でフローが続行されますtf finally

知っておくべき主な意味と、あなたが提案する方法で修正できない可能性があると思いますが、それは次のとおりです。

  1. 2 番目の例のようにコードを実装すると、必ずしもtcリソースtfにアクセスしてクリーンアップできるとは限りません。
  2. できたとしても、リソースの使用状況に近くないレイヤーでリソースをクリーンアップしており、フレームワークの他のクライアント コードでも使用されていない可能性があります。それはドキュメンテーションとトレーニングの問題だと思います。
于 2013-01-24T09:15:30.797 に答える
1

どちらも同じです。しかし、最終的には、途中で関数を壊す危険がある場合、または関数によって保持されているリソースを解放したい場合に使用されます。その場合、catch はスキップされますが、最終的には確実に実行されます。

try は、catch または finally またはその両方と一緒に使用できます。最終的には、通常、発生した例外を表示することはできませんが、catch は例外を追跡できます。

于 2013-01-24T09:13:36.023 に答える