Jak*_* M. 9 java stack exception-handling exception
我想了解try {} catch {}
块和堆栈跟踪如何工作的内部结构.
我正在阅读这篇关于异常处理反模式的伟大文章,并发现以下段落:
Run Code Online (Sandbox Code Playgroud)catch (NoSuchMethodException e) { throw new MyServiceException("Blah: " + e.getMessage()); }
这会破坏原始异常的堆栈跟踪,并且总是错误的.
从那以后,我意识到,我并不真的知道如何try/catch
工作的.我的理解如下.考虑这个例子:
void top() {
try {
f();
} catch (MyException ex) {
handleIt();
} finally {
cleanup();
}
}
void f() {
g();
}
void g() {
throw new MyException();
}
Run Code Online (Sandbox Code Playgroud)
当我调用时top()
,调用链 在调用堆栈上top -> f -> g
留下两个堆栈帧(for top
和f
functions).当引发异常时g
,程序会冒出执行堆栈,直到找到try/catch
处理异常的块.同时,它释放堆栈帧并将堆栈跟踪信息附加到可以传递到的一些"魔术"对象,catch
并且可以打印堆栈跟踪.
怎么知道被调用的函数被try/catch块"包围"了?此信息是否绑定到堆栈帧?比如,指向错误处理块的指针(某些开关选择匹配catch
块)和指向finally
块的指针?为什么e.getMessage()
在上面的例子中是破坏性的(见评论)?
请注意,我知道如何使用try/catch语句和例外情况,我想知道它是如何工作的内部.
"它如何知道被调用的函数被try/catch块"包围"了?"
每个方法的代码都包含Exception Table,它描述了该方法的所有try-catch块.
当调用过程(函数,方法)时,当前堆栈帧附加有调用指令的地址,以便在正确的指令(调用指令之后的下一个)恢复该帧的执行.
执行throw语句时,JVM 会检查每个堆栈帧 以确定该帧是否可以处理异常.它可以包含一个包含调用指令的try-catch块,并且块的异常类型是抛出异常的超类型(或相同).如果找到这样的帧,则帧从指向try-catch块的指令恢复其执行.