英文:
Avoiding exception hiding when finally block could throw
问题
Here's the translated content:
当你有一个包装在try-catch-finally中的进程,并且最终的操作可能会引发异常时,如何处理异常隐藏?
这是一个问题和可能的修复示例。修复看起来是否可以,或者我是不是处理异常不当?
具有隐藏问题的代码
try {
// try块
setupTestEnv();
runTests();
} finally {
// finally块
cleanupTestEnv();
}
- try块引发的异常仍然会导致清理并沿着调用堆栈抛出
- 在try块引发异常的情况下,如果finally块也引发异常,那么try块引发的异常会被隐藏或覆盖,因为finally块引发的异常会沿着调用堆栈传播。
可能的解决方法
改编自https://stackoverflow.com/a/41246027/9950
Throwable tryBlockException;
try {
setupTestEnv();
runTests();
} catch (Throwable t) {
// 记录并抛出异常
tryBlockException = t;
throw t;
} finally {
try {
cleanupTestEnv();
} catch (Throwable t) {
if (tryBlockException != null) {
// 我们有来自try块的异常
// 这是优先级更高的异常
// 将清理异常添加为被抑制的异常
// 它将在对象和调用报告中显示
tryBlockException.addSuppressed(t);
throw tryBlockException;
} else {
throw t;
}
}
}
英文:
When you have a process which you’ve wrapped in a try catch, finally, and the action in the final could possibly throw, how do you handle exception, hiding?
Here's an example of a problem and a possible fix. Does the fix look ok, or am I re-throwing poorly?
Code with Hiding Problem
try {
// try-block
setupTestEnv();
runTests();
} finally {
// finally-block
cleanupTestEnv();
}
- try-block throws still result in cleanup and get thrown up the call stack
- try-block throws where finally-block throws as well result in the loss or hiding of try-block throw as finally-block throw goes up the call stack.
Possible Workaround
Adapted from https://stackoverflow.com/a/41246027/9950
Throwable tryBlockException;
try {
setupTestEnv();
runTests();
} catch (Throwable t) {
// record and throw
tryBlockException = t;
throw ex;
} finally {
try {
cleanupTestEnv()
} catch (Throwable t) {
if (tryBlockException != null) {
// we have an exception from try-block
// and that's priority exception
// add the cleanup exception as suppressed
// it'll be in the object and call reporting
tryBlockException.addSuppressed(t);
throw tryBlockException;
} else {
throw t;
}
}
}
答案1
得分: 1
以下是翻译好的部分:
"Looks fine to me. I would suggest putting the bulk of the code into a re-usable method, e.g.:
public interface Attempt {
void apply() throws Exception;
}
public static void tryCatchFinally(
Attempt mainF,
Attempt finallyF
) throws Exception {
Exception tryCatchException = null;
try {
mainF.apply();
} catch (Exception ex) {
tryCatchException = ex;
throw ex;
} finally {
try {
finallyF.apply();
} catch (Exception ex) {
if (tryCatchException != null) {
tryCatchException.addSuppressed(ex);
}
}
}
}
then you can just use it like this:
tryCatchFinally(
() -> {setupTestEnv(); runTests();},
() -> cleanupTestEnv()
);"
请告诉我您是否需要进一步的帮助。
英文:
Looks fine to me. I would suggest putting the bulk of the code into a re-usable method, e.g.:
public interface Attempt {
void apply() throws Exception;
}
public static void tryCatchFinally(
Attempt mainF,
Attempt finallyF
) throws Exception {
Exception tryCatchException = null;
try {
mainF.apply();
} catch (Exception ex) {
tryCatchException = ex;
throw ex;
} finally {
try {
finallyF.apply();
} catch (Exception ex) {
if (tryCatchException != null) {
tryCatchException.addSuppressed(ex);
}
}
}
}
then you can just use it like this:
tryCatchFinally(
() -> {setupTestEnv(); runTests();},
() -> cleanupTestEnv()
);
答案2
得分: 0
这是一种方法,除了在您的情况下,不是"t",而是"tryblockexception"被抑制了,您不需要重新抛出"tryblockexception"。
其他选项包括使用"try-with-resources"来自动关闭类型,或者在可能的情况下确保"finally"子句不会抛出异常,因为它可能会吞噬"try"块中的异常。
英文:
That's a way to go except that in your case it's not t but tryblockexception which is suppressed and you don't need to rethrow tryblockexception neither.
Other options are try-with-resources for autocloseable type or when possible making sure that the finally clause does not throw ex because it can swallow exceptions from the try block.
答案3
得分: 0
我不确定为什么你要以这种复杂的方式使用finally
。你也可以只使用在try-catch块之后运行的代码:
Exception priorityException;
try {
setupTestEnv();
runTests();
} catch (Exception ex) {
priorityException = ex; // 延迟处理
}
try {
cleanupTestEnv();
} catch (Exception ex) {
if (priorityException != null) {
priorityException.addSuppressed(ex);
} else {
priorityException = ex;
}
throw priorityException;
}
请注意,我使用了catch (Exception ...)
而不是你的Throwable
,因为通常无法以有用的方式捕获和处理Error
。查看Stack Overflow问题Catching Java errors以及其中的答案,以获得更好的了解。
英文:
I'm not sure why you have to use a finally
in such a complex way. You could also just use code that runs after the try-catch block:
Exception priorityException;
try {
setupTestEnv();
runTests();
} catch (Exception ex) {
priorityException = ex; // delayed handling
}
try {
cleanupTestEnv();
} catch (Exception ex) {
if (priorityException != null) {
priorityException.addSuppressed(ex);
} else {
priorityException = ex;
}
throw priorityException;
}
Please note that I used a catch (Exception ...)
instead of your Throwable
because catching and handling Error
s is usually not possible in a useful way. See SO question Catching Java errors and its answers for better insight.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论