Exception Table 是 JVM 在 class 文件中为每个方法维护的异常处理路由表,记录 try 块字节码范围(from/to)、异常处理器入口(target)及捕获类型(type),决定异常抛出时跳转到哪个 catch 或 finally 块执行。
Exception Table 是什么:字节码里 catch 块的“路由表”
它不是 Java 语法层面的概念,而是 JVM 在
文件里为每个方法记录的一张小表格,告诉 JVM:“当从
到
这段字节码抛出类型为
的异常时,跳转到
执行处理逻辑”。没有这张表,
就没法在运行时定位该进哪个
块。
常见错误现象:
块完全没触发,或者抛出异常后直接
(极少见但可能因表损坏);反编译看到
区域有字节码,却找不到对应
的跳转逻辑——大概率是 Exception Table 没生成或被优化掉了。
只对
块内实际可能抛出的异常类型生成条目,比如
,但
里全是
,JVM 可能压根不写这条目
和
是字节码偏移量,不是行号;它们包含的是
块中所有指令的起止位置,包括隐式抛出点(如数组访问越界)
多个
会生成多条表项,顺序很重要:JVM 从上到下匹配,所以更具体的异常类型(如
)要写在更宽泛的(如
)前面
怎么看 Exception Table:用
java
p -v 看真实结构
别信 IDE 的高亮或反编译器的伪代码,
输出的才是 JVM 实际加载的内容。关键字段就四个:
、
、
、
(对应 spec 中的
/
/
/
)。
使用场景:排查“明明写了 catch 却没进”的问题,或者验证某个异常是否真被当前
捕获(比如
跨了方法调用,但异常实际发生在 callee 里)。
立即学习
“
Java免费学习笔记(深入)
”;
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
和
是闭区间,
指向的是
块**之后一条指令**的偏移,不是
最后一条指令
为
表示
块(JVM 把
当作一种特殊 handler),不是异常类型
如果
里有嵌套
,外层表项的
会覆盖整个外层范围,内层单独再列条目
为什么 finally 总是生效:它靠 Exception Table 的 type=0 条目驱动
不是靠“插桩”或“语法糖后置”,而是 JVM 强制为每个
(无论有没有
)生成至少一条
的表项,覆盖整个
范围,并指向
对应的字节码起点。哪怕
里
了,JVM 也会在真正返回前跳过去执行
块。
容易踩的坑:
里又
或抛异常,会吞掉
或
中的返回值或异常——这不是 Exception Table 的错,但它的存在让这个行为成为 JVM 层面的确定性规则。
即使
块空着(
),
仍存在,且
指向
入口
编译后本质是
,所以也依赖 type=0 条目,资源关闭逻辑就放在那个
处
如果
块本身抛出异常,原异常会被丢弃(除非用
显式关联)
编译器优化会影响 Exception Table 吗:会,但只在极端情况下
现代
(尤其是 JDK 11+)会对明显不会抛异常的代码块省略对应表项,比如
后跟
,JVM 可能直接不生成该条目。但这不影响语义——因为那块代码真不会抛异常。
性能影响几乎为零:Exception Table 是只读元数据,查找是 O(n) 但 n 极小(通常 ≤5),且仅在异常实际抛出时才查;日常无异常路径完全不碰它。
混淆工具(如 ProGuard)若未保留
和
,Exception Table 仍完整,但调试时无法映射回源码行号
AOT 编译(如 GraalVM native-image)会把 Exception Table 静态固化进二进制,但语义不变
最易被忽略的点:Lambda 表达式里的
,其 Exception Table 属于生成的合成方法(如
),不是外围方法
Exception Table 是 JVM 实现异常语义的底层契约,它不抽象、不隐藏,就明明白白写在 class 文件里——你改一行 Java 代码,它就可能增删一条表项。理解它,不是为了手写字节码,而是当 catch 不工作时,知道该去
里盯哪几列。
classstart_pcend_pccatch_typehandler_pctry-catchcatchcatchOutOfMemoryErrortrycatchtrycatch (IOException e)tryMath.abs()start_pcend_pctrycatchNullPointerExceptionExceptionjavap -vfromtotargettypestart_pcend_pchandler_pccatch_typetrytryfromtototrytrytype0finallyfinallytrytry-catchfrom/to
Exception table:
from to target type
0 15 18 Class java/io/IOException
0 15 25 Class java/lang/Exception
18 23 25 Class java/lang/Exception
finallytrycatchtype = 0tryfinallytryreturnfinallyfinallyreturntrycatchtrytry {} finally {}from/totargetfinallytry-with-resourcestry-finallytargetfinallyaddSuppressedjavactry { int x = 1 + 2; }catch (Exception e)LineNumberTableLocalVariableTabletry-catchlambda$foo$0javap -v