作者回复: 思考得很深,赞一个!
即时编译器生成的代码会保存原始的栈信息,以便去优化时能够复原。fillStackTrace也会读取这些信息的,所以不用先去优化再fill。
抛异常本身带来了额外的执行路径。通常如果能够将异常处理器也编译进去,那么不会有太大影响。
作者回复: catch里抛的异常会被finally捕获了,再执行完finally代码后重新抛出该异常。由于finally代码块有个return语句,在重新抛出前就返回了。
你可以利用这篇文章的知识,就着javap的输出,分析一下具体的程序路径
作者回复: 1 检查异常这个概念只在源代码中出现。异常表不是声明这段代码所有有可能抛出的异常,而是声明会被捕获的异常。
2 会的
3 栈轨迹 跟 弹出方法栈帧 是两个概念。你可以直接新建一个异常,然后不抛出,直接打印调用栈。这个时候是不会弹出当前栈帧的。
作者回复: 理论上是可以的,一般不这么做,原因有两个,一是异常路径无需考虑性能,二是代码可读性。
作者回复: 编译期异常和运行时异常这种划分有点奇怪。
检查异常也会在运行过程中抛出。但是它会要求编译器检查代码有没有显式地处理该异常。非检查异常包括Error和RuntimeException(会不会那本书直译为”运行时异常”?),这两个则不要求编译器显式处理。
作者回复: 首先走抛出异常捕获异常的异常执行路径的话,性能肯定是很慢的,因此最好在参数出现问题的概率很小的情况下使用这种方式。
另外,你说的Assert是某个库的工具类,还是assert语句?后者的话,一般只在开发环境中启用吧。
作者回复: 前者指Throwable.fillStackTrace以及异常的构造器,后者为Java虚拟机不想让用户看到的栈帧,比如说方法句柄的适配器类中的方法。之后讲Lambda时会有具体的例子。
作者回复: 你可以整个方法用try catch 包住,捕获Throwable并在异常处理器中写日志,并用throw语句重新抛该异常