由于这是一个关于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子句,应该被认为是不好的做法?
答案 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();
}
这也可以。