嵌套这样的try / finally子句是否安全?

时间:2013-03-18 09:39:32

标签: java nested try-finally

由于这是一个关于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()之前是否保证closeDatabaseConnection()被调用。有没有理由嵌套一个finally子句,应该被认为是不好的做法?

5 个答案:

答案 0 :(得分:4)

是的,保证。

useCursor(cursor_id)期间发生了一些异常,现在将执行 inner finally 块。 (因为异常发生在内部try块中)。在调用此genericLogError()之后(因为包含内部try的外部try发生了异常。只有在closeDatabasConnection()执行后才会执行finally外部try)。这是一个可以更好地解释它的图表:

(内部尝试中的异常→内部尝试的最终结果)这被视为外部尝试外部尝试的捕获< / strong>→最终的外部尝试。

您可以通过从块中打印来测试它。

但为什么不这样做?

try {
  useCursor(cursor_id);
} catch(Exception e) {
  genericLogError();
} finally {
  closeCursor(cursor_id);
  closeDatabaseConnection();
}

答案 1 :(得分:3)

这没有任何问题,假设您需要首先嵌套这样的try-catch块。对于您提供的示例,Maroun's回答会更好。您建议的方法更合适的示例可能是如果您在“光标”清理中涉及许多局部变量:

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块中。

如果你想将所有这些代码都放到一个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();
}

答案 2 :(得分:1)

是的,closeCursor()保证在closeDatabaseConnection()之前被调用,在这种情况下。

您可以将两个来电置于一个finally区块中(将来电closeCursor()移至您呼叫finally的同一个closeDatabaseConnection()区块),但这需要声明光标在外部范围内,这可能是不可取的。例如,您可能希望将所有使用游标的代码放入单独的方法中;在这种情况下,您可能希望使用finally块来关闭此新方法中的游标。

一般来说,我认为finally条款的嵌套不应被视为不良做法。我们应该考虑代码的一般可读性,例如一个方法中的行数 - 可能最好将方法拆分为两个,在这种情况下会有两个finally块,每个方法一个。或者,如果您的代码简单且足够短,可以在一个方法中使用,则可以重新组织代码以仅使用一个finally块。

答案 3 :(得分:1)

当控制离开try块时,保证执行finally子句。这里控件在外部块之前留下内部try块,因此保证了执行顺序。

除了你正在制作一个可以分成两个或更多的大方法之外,没有理由认为这应该被认为是不好的做法。

答案 4 :(得分:0)

使用try / chatch然后最后。
然后你的代码很好 关闭光标,连接始终和这里是一个很好的编码实践  在致电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();
    }

或者你可以移除内部尝试并且可以在外部最终自身关闭两者,如:

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

这也可以。