7

これは、try/finally 句の動作に関するやや学術的な質問であるため、非常に一般的な例を使用しようとしました。このように try/finally 句をネストすることに危険はありますか?

openDatabaseConnection();
try {
    // Methods unrelated to cursor
    // ...

    String cursor_id = openCursor();
    try {
        useCursor(cursor_id);
    } finally {
        closeCursor(cursor_id);
    }

    // Methods unrelated to cursor
    // ...
} catch (Exception e) {
    genericLogError();
} finally {
    closeDatabaseConnection();
}

closeCursor()具体的には、が before で呼び出されることが保証されているかどうかを知りたいですcloseDatabaseConnection()。悪い習慣と見なされるように、finally 句をネストする理由はありますか?

4

5 に答える 5

5

はい、保証されています。

中に何らかの例外が発生したとします。useCursor(cursor_id)今度は内側の finallyブロックが実行されます。(内部tryブロックで例外が発生したため)。これgenericLogError()が呼び出された後 (tryインナーを含むアウターで例外が発生したためtry。そして、それcloseDatabasConnection()が実行された後でのみ (finallyアウターのtry)。これをよりよく説明する図を次に示します。

(インナートライでの例外→インナートライのfinally)これはアウタートライの例外とみなす→アウタートライキャッチ→アウタートライのfinally。

ブロックから印刷してテストできます。

しかし、なぜこのようにしないのですか?

try {
  useCursor(cursor_id);
} catch(Exception e) {
  genericLogError();
} finally {
  closeCursor(cursor_id);
  closeDatabaseConnection();
}
于 2013-03-18T09:42:29.377 に答える
3

そもそもこのように try-catch ブロックをネストする必要があると仮定すると、これに問題はありません。Maroun の答えは、あなたが提供した例に適しています。あなたが提案したアプローチがより適している例は、「カーソル」のクリーンアップに多くのローカル変数が含まれている場合です。

openDatabaseConnection();
try {
    Cursor cursor = openCursor();
    CursorHelper helper = new CursorHelper(cursor);
    String cursor_id = cursor.getId();
    String something_else = cursor.getSomethingElse();
    try {
        useCursor(cursor_id, something_else, helper);
    } finally {
        closeCursor(cursor_id, something_else, helper);
    }
} catch (Exception e) {
    genericLogError();
} finally {
    closeDatabaseConnection();
}

親の try ブロックは、ネストされたブロックによってスローされた例外をキャッチしますが、ネストされたfinallyブロックが最初に呼び出されます。try/catchこれにより、最初のブロック内にカプセル化されたカーソル変数のスコープが保持されます。

このすべてのコードを 1 つのtry/catchブロックにまとめたい場合は、一部の変数をブロックの外で宣言する必要があり、可読性に影響を与える可能性があります。

openDatabaseConnection();
CursorHelper helper = null;
String cursor_id = null;
String something_else = null;
try {
    Cursor cursor = openCursor();
    helper = new CursorHelper(cursor);
    cursor_id = cursor.getId();
    something_else = cursor.getSomethingElse();
    useCursor(cursor_id, something_else, helper);
} catch (Exception e) {
    genericLogError();
} finally {
    if (cursor_id != null) {
        closeCursor(cursor_id, something_else, helper);
    }
    closeDatabaseConnection();
}
于 2013-03-18T09:59:13.430 に答える
1

はい、この場合は のcloseCursor()前に呼び出されることが保証されています。closeDatabaseConnection()

両方の呼び出しを 1 つのfinallyブロックに入れることもできます (呼び出しをcloseCursor()を呼び出した同じfinallyブロックに移動しますcloseDatabaseConnection()) が、それにはカーソルを外側のスコープで宣言する必要があり、望ましくない場合があります。たとえば、カーソルを操作するすべてのコードを別のメソッドに入れたい場合があります。finallyこの場合、おそらくこの新しいメソッドでカーソルを閉じるブロックが必要になるでしょう。

finally一般に、節の入れ子を悪い習慣と見なすべきではないと思います。1 つのメソッドの行数など、コードの一般的な可読性を考慮する必要があります。おそらく、メソッドを 2 つに分割した方がよいでしょう。この場合finally、各メソッドに 1 つずつ、2 つのブロックがあります。または、コードが単純で、1 つのメソッドに収まるほど短い場合は、コードを再編成して 1 つのfinallyブロックのみにすることができます。

于 2013-03-18T09:45:20.410 に答える
0

try/chatch を使用してから、finally を使用します。
そして、あなたのコードは問題ありません。
カーソル、接続を常に閉じることは良いコーディングの実践であり、ここでは正確に行った呼び出しのcloseCursor(cursor_id)前に呼び出す必要があります。 最終ブロックは常に実行されますが、それぞれのブロックの実行中にいくつか発生するため、ここではコードカーソルが最初に閉じられ、次にデータベース接続が閉じられるため、これは完璧です。 参照用に変更されたコード スニペットを見つけてください。closeDatabaseConnection()
Exception

 openDatabaseConnection()
    try {
        // Methods unrelated to cursor
        // ...

        String cursor_id = openCursor();
        try {
            useCursor(cursor_id);
        } 
        catch (Exception e) { //Added the catch block.
        genericLogError();
       } 
        finally {
            closeCursor(cursor_id);
        }

        // Methods unrelated to cursor
        // ...
    } catch (Exception e) {
        genericLogError();
    } finally {
        closeDatabaseConnection();
    }

または、内側の try を削除して、次のように外側の最終的に両方を閉じることができます。

//outer try block
try{
....
}catch(Exception e){
genericLogError();
}
finally {
         closeCursor(cursor_id);
        closeDatabaseConnection();
    }

これも行います。

于 2013-03-18T09:45:01.167 に答える