当前位置: 首页 > news >正文

try-catch-finally的字节码原理

Java 中有一个非常重要的内容是 try-catch-finally 的执行顺序和返回值问题,其中 finally 一定会执行,但是为什么会这样? 下面看下 try-catch-finally 背后的实现原理

try-catch

public class Test {public static void main(String[] args) {foo();}public static void foo() {try {int i = 1 / 0;}catch (Exception e){System.out.println("执行异常");e.printStackTrace();}}}

字节码

public class com.yxzapp.Test {public com.yxzapp.Test();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: invokestatic  #2                  // Method foo:()V3: returnpublic static void foo();Code:0: iconst_1                         // 将int 类型值1压栈到栈顶1: iconst_0						   // 将int 类型值0压栈到栈顶2: idiv                             // 将栈顶两int型数值相除并将结果压入栈顶3: istore_0                         // 将栈顶类型int数据存储到局部变量表下标04: goto          20                 // 如果不抛异常跳到20行7: astore_0                         // 将引入对象(异常对象)存储局部变量表下标08: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;11: ldc           #5                  // String 鎵ц寮傚父13: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V16: aload_017: invokevirtual #7                  // Method java/lang/Exception.printStackTrace:()V20: returnException table:from    to  target type0     4     7   Class java/lang/Exception
}

17 4: goto 20 // 如果不抛异常跳到20行

如果有异常抛出,如何处理呢?

当方法包含 try-catch 语句时,在编译单元生成的方法的 Code 属性中会生成一个异常表 (Exception table), 每个异常项表示一个异常处理器, 由 from 指针 、to 指针、target 指针 、所捕获的异常类型 type 四部分组成。这些指针的值是字节码索引,用于定位字节码。其含义是在 [from ,to) 字节码范围内,如果跑出来异常类型为 type 的异常,就会跳转到 target 指针表示的字节码处继续执行。

上面的例子中 Exception table表示,在 0 - 4 之间(不包含4),如果抛出类型为 Exception 或其子类就跳转到7继续执行

当抛出异常时,Java 虚拟机会自动将异常对象加载到操作数栈栈顶

多try-catch

public class Test {public static void main(String[] args) {foo();}public static void foo() {try {int i = 1 / 0;}catch (ArithmeticException e){System.out.println("执行异常 ArithmeticException");e.printStackTrace();} catch (NullPointerException e){System.out.println("执行异常 NullPointerException");e.printStackTrace();}}}

字节码

public class com.yxzapp.Test {public com.yxzapp.Test();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: invokestatic  #2                  // Method foo:()V3: returnpublic static void foo();Code:0: iconst_11: iconst_02: idiv3: istore_04: goto          367: astore_08: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;11: ldc           #5                  // String 鎵ц寮傚父 ArithmeticException13: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V16: aload_017: invokevirtual #7                  // Method java/lang/ArithmeticException.printStackTrace:()V20: goto          3623: astore_024: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;27: ldc           #9                  // String 鎵ц寮傚父 NullPointerException29: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V32: aload_033: invokevirtual #10                 // Method java/lang/NullPointerException.printStackTrace:()V36: returnException table:from    to  target type0     4     7   Class java/lang/ArithmeticException0     4    23   Class java/lang/NullPointerException
}

可以看到 ,多一个 catcha 语句处理分析, 异常表里面就会多一条记录,当程序出现异常时, Java 虚拟机会从上至下遍历异常表中所有的条目。当触发异常的字节码索引值在某个条目的 [from 、to)范围内,则会判断抛出的异常是否是想捕获的异常或子类

如果异常匹配, Java 虚拟机将控制跳转到 target 指向的字节码继续执行;如果不匹配,则继续遍历异常表。如果遍历完所有的异常表还未找到匹配的异常处理器,那么该异常将继续抛到调用方 (caller)中重复上述的操作

try-catch-finally

public class Test {public static void main(String[] args) {foo();}public static void foo() {try {int i = 1 / 0;}catch (ArithmeticException e){System.out.println("执行异常 ArithmeticException");e.printStackTrace();} finally {System.out.println("执行");}}}

字节码

public class com.yxzapp.Test {public com.yxzapp.Test();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: invokestatic  #2                  // Method foo:()V3: returnpublic static void foo();Code:0: iconst_1                          // 将int 类型值1压栈到栈顶1: iconst_0                          // 将int 类型值0压栈到栈顶2: idiv                              // 将栈顶两int型数值相除并将结果压入栈顶3: istore_0							// 开始执行 finally 代码块4: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;7: ldc           #4                  // String 鎵ц9: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V12: goto          5015: astore_0// 异常(被catch)情况下开始执行 finally 代码块16: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;19: ldc           #7                  // String 鎵ц寮傚父 ArithmeticException21: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V24: aload_025: invokevirtual #8                  // Method java/lang/ArithmeticException.printStackTrace:()V28: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;31: ldc           #4                  // String 鎵ц33: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V36: goto          5039: astore_1// 异常(catch中执行出现异常)代码块出现异常 情况下开始									   执行 finally 代码块40: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;43: ldc           #4                  // String 鎵ц45: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V48: aload_149: athrow50: returnException table:from    to  target type0     4    15   Class java/lang/ArithmeticException0     4    39   any15    28    39   any
}

可以看出字节码中 出现三次调用

   getstatic     #3                     // Field java/lang/System.out:Ljava/io/PrintStream;ldc           #4                        // String 鎵цinvokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

都是在程序正常 return 和异常 throw 之前,其中两处在 try-catch 语句调用 return 之前,一处是在异常抛出 throw 之前

由代码可知,现在的 Java 编译器采用复制 finally 代码块的方式,并将其内容插入到 try 和 catch 代码块中所有正常退出和异常退出之前。这样就解释了我们一直以来所熟知的 finally 语句块一定会执行

相关文章:

try-catch-finally的字节码原理

Java 中有一个非常重要的内容是 try-catch-finally 的执行顺序和返回值问题&#xff0c;其中 finally 一定会执行&#xff0c;但是为什么会这样&#xff1f; 下面看下 try-catch-finally 背后的实现原理 try-catch public class Test {public static void main(String[] args)…...

基于双层优化的微电网系统规划设计方法(Matlab代码实现)

目录 &#x1f4a5;1 概述 1.1 微电网系统结构 1.2 微电网系统双层规划设计结构 1.3 双层优化模型 1.4 上层容量优化模型 1.5 下层调度优化模型 &#x1f4da;2 运行结果 &#x1f389;3 文献来源 &#x1f308;4 Matlab代码、数据、文章讲解 &#x1f4a5;1 概述 文献来源&…...

【Nginx13】Nginx学习:HTTP核心模块(十)Types、AIO及其它配置

Nginx学习&#xff1a;HTTP核心模块&#xff08;十&#xff09;Types、AIO及其它配置 今天学习的内容也比较简单&#xff0c;主要的是 Types 相关的配置&#xff0c;另外还会了解一下 AIO 以及部分没有特别大的分类归属的配置指令的使用。后面的内容都是 HTTP 核心模块中比较小…...

2023年华数杯数学建模C题思路分析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor 1 竞赛信息 为了培养学生的创新意识及运用数…...

安卓手机变身Linux服务器

文章目录 前言一、准备工作1、安卓手机2、下载软件二、开始安装1、检查系统,确认版本并安装2、配置(安卓7.0 及以上的用户忽略此步)3、问题处理【没有异常的小伙伴忽略】总结前言 在实际开发中有很多地方都需要服务器资源,但是服务器资源不论在哪里都是比较紧缺的资源,今…...

【Ansible】Ansible自动化运维工具之playbook剧本

playbook 一、playbook 的概述1. playbook 的概念2. playbook 的构成 二、playbook 的应用1. 安装 httpd 并启动2. 定义、引用变量3. 指定远程主机 sudo 切换用户4. when条件判断5. 迭代6. Templates 模块6.1 添加模板文件6.2 修改主机清单文件6.3 编写 playbook 7. tags 模块 …...

Yolov8目标检测

Yolov8目标检测 目录 Yolov8目标检测一、准备数据集二、源码下载配置2.1 下载库2.2 修改配置2.3 训练2.4 验证2.5 测试2.6 模型导出2.7 本地测试 一、准备数据集 Yolov8只支持yolo格式的数据&#xff0c;所以&#xff0c;需要将数据集格式调整为 datasets|images|train|00000…...

Jmeter用于接口测试中,关联如何实现

Jmeter用于接口测试时&#xff0c;后一个接口经常需要用到前一次接口返回的结果&#xff0c;应该如何获取前一次请求的结果值&#xff0c;应用于后一个接口呢&#xff0c;拿一个登录的例子来说明如何获取。 1、打开jmeter, 使用的3.3的版本&#xff0c;新建一个测试计划&#x…...

线程状态

从卖包子的案例学习进程间的通信 public class Test {public static void main(String[] args) {Object objnew Object();Thread th1new Thread(){Overridepublic void run() {synchronized (obj){System.out.println("来三个包子&#xff01;");try {obj.wait(); /…...

HTML一些基础知识

1、Web标准&#xff1a;主要包含结构、表现、行为。结构用于对网页元素进行整理和分类&#xff0c;主要指HTML。表现用于设置网页元素的板式、颜色、大小等外观样式&#xff0c;主要指的是CSS。行为主要指的是网页模型的定义以及交互的编写&#xff0c;主要是js文件。 Html相当…...

git 命令总结

一、本地分支和仓库里的分支不同步&#xff08;本地看不到最新的分支&#xff09; 1.使用 git fetch origin 或者git remote update origin --prune命令更新 2.git branch -r 查看 即可 二、git 合并代码 1. git 如何把分支代码合并到master 1.1 首先切换到分支 git checkou…...

【Django】如何优化数据库访问

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、数据库层面优化常用优化postgresql查询分库分表 二、内存层面优化三、代码层面优化 前言 Django是一个高级的Web框架&#xff0c;它…...

常压室温超导材料:揭开物理学的新篇章

常压室温超导材料&#xff1a;揭开物理学的新篇章 目录 引言超导现象简介常压室温超导材料的重要性常压室温超导材料的研究进展常压室温超导材料的挑战与前景结论 1. 引言 自从1911年荷兰物理学家海克卡默林奥涅斯发现超导现象以来&#xff0c;超导技术在许多领域都有着广泛…...

【《C# 10 和 .NET 6入门与跨平台开发(第6版)》——一本循序渐进的C#指南】

这个新版本对上一版做了全面修订&#xff0c;涵盖C# 10和.NET 6的所有新功能. 本书讨论面向对象编程、编写函数、测试函数、调试函数、实现接口以及继承类等主题&#xff1b;介绍.NET API&#xff0c;这些API可执行多种任务&#xff0c;如管理和查询数据&#xff0c;监视和改进…...

2.5 BUMP图改进

一、Bump Mapping介绍 凹凸贴图映射技术是对物体表面贴图进行变化然后进行光计算的一种技术。例如给法线分量添加噪音&#xff0c;或者在一个保护扰动值的纹理图中进行查找。这是一个提升物理真实感的有效方法&#xff0c;但却不需要额外的提升物体的几何复杂度。这种法式在提…...

第六篇-ChatGLM2-6B-CentOS7安装部署-GPU版

环境 系统&#xff1a;CentOS-7 CPU: 14C28T 显卡&#xff1a;Tesla P40 24G 驱动: 515 CUDA: 11.7 cuDNN: 8.9.2.26模型文件 https://huggingface.co/THUDM/chatglm2-6b 下载模型相关文件到自己目录 我的是/models/chatglm2-6b [rootai-server chatglm2-6b]# pwd /models/c…...

dotnet 依赖注入-批量注入Controller,service,Dao

此类为扩展注入类&#xff0c;使用autofuc 仅供参考 注入接口和实现。 使用方法&#xff1a; //配置项调用ConfigContainer public void ConfigureContainer(ContainerBuilder builder){TestMicroService.ConfigContainer(builder);} //service调用RegisteApiController …...

【Spring】Spring对IoC的实现

根据 【动力节点】最新Spring框架教程&#xff0c;全网首套Spring6教程&#xff0c;跟老杜从零学spring入门到高级 以及老杜的原版笔记 https://www.yuque.com/docs/share/866abad4-7106-45e7-afcd-245a733b073f?# 《Spring6》 进行整理&#xff0c; 文档密码&#xff1a;mg9b…...

正则表达式中的大括号-花括号{}有什么用?

在正则表达式中&#xff0c;花括号 {} 是用于指定匹配次数的量词元字符。它可以用来表示匹配的次数范围或精确匹配次数。 具体来说&#xff0c;花括号 {m} 表示前面的模式匹配恰好出现 m 次&#xff0c;而 {m, n} 表示前面的模式匹配出现 m 到 n 次。 以下是一些常见的用法示…...

Flutter 状态栏完美攻略

1. 沉浸式状态栏 Scaffold(extendBodyBehindAppBar: true,appBar: AppBar(toolbarHeight: 0,),body: Container(color:Colors.red) ) 2. 状态栏的背景颜色 Scaffold(appBar: AppBar(backgroundColor: Colors.transparent,),body: Container(color:Colors.red) ) 3. 状态栏的…...

1688代采系统开发避坑指南:经验之谈

做跨境代购系统三年了&#xff0c;技术栈换过一次。今天把当初的技术选型过程和踩坑经验整理出来。多页面架构&#xff08;MPA&#xff09;的选择&#xff1a;没有用 React/Vue SPA 做租户端前台的首页和商品页&#xff0c;而是传统的多页面&#xff08;HTML JS jQuery&#…...

MakeMeAHanzi完整指南:如何免费获取9000+汉字笔画动画数据

MakeMeAHanzi完整指南&#xff1a;如何免费获取9000汉字笔画动画数据 【免费下载链接】makemeahanzi Free, open-source Chinese character data 项目地址: https://gitcode.com/gh_mirrors/ma/makemeahanzi MakeMeAHanzi是一个免费开源的汉字数据项目&#xff0c;为开发…...

【Lovable前端开发实战指南】:20年专家亲授5个让团队抢着用的可维护性设计模式

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;Lovable前端开发的核心理念与可维护性本质 Lovable前端开发并非追求炫酷动效或技术堆砌&#xff0c;而是以人本设计为原点&#xff0c;将开发者体验&#xff08;DX&#xff09;与用户界面体验&#xff08;UX&a…...

锂电池健康评估:避开NASA/Oxford数据IC分析中的三个常见坑(滤波、异常值、容量增生)

锂电池健康评估实战&#xff1a;破解NASA/Oxford数据集IC分析的三重困局 当你在深夜盯着屏幕上那些扭曲的IC曲线时&#xff0c;是否也经历过这样的崩溃时刻&#xff1f;明明按照教科书步骤处理NASA数据集&#xff0c;得到的却是锯齿状的噪声图形&#xff1b;或是发现Oxford数据…...

原神抽卡数据分析终极指南:免费开源工具助你告别抽卡迷茫

原神抽卡数据分析终极指南&#xff1a;免费开源工具助你告别抽卡迷茫 【免费下载链接】genshin-wish-export Easily export the Genshin Impact wish record. 项目地址: https://gitcode.com/GitHub_Trending/ge/genshin-wish-export 还在为原神抽卡记录无法保存而烦恼吗…...

2026年项目交付排期系统选型指南:10款主流工具深度测评

一、为什么你的项目总是交付延期&#xff1f;进入2026年&#xff0c;多项目并行、跨地域协作、人力资源紧张、需求频繁变更&#xff0c;已经成为各行业项目推进的常态化现状。当下多数项目出现交付延期问题&#xff0c;核心原因往往并非团队执行效率不足&#xff0c;而是项目排…...

从入门到发烧:2026 Linux 必装 13 款播放器(VLC/MPV/Kodi 全覆盖)

Linux视频播放器选择多样&#xff0c;如榛名、MPlayer、VLC等&#xff0c;功能强大、支持多格式&#xff0c;满足各类用户需求 一、榛名视频播放器 榛名视频播放器是一款基于Qt的开源视频播放器&#xff0c;提供了许多基本功能。其特点包括支持Youtube-dl、控制播放速度、丰富…...

为什么92%的NotebookLM项目在第3轮迭代后风格失控?——基于17个真实客户日志的归因分析与防御协议

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;为什么92%的NotebookLM项目在第3轮迭代后风格失控&#xff1f;——基于17个真实客户日志的归因分析与防御协议 在对17个企业级NotebookLM部署案例进行全链路日志回溯后&#xff0c;我们发现一个高度一致…...

AI智能切片不是‘一键分割’就完事:批量口播视频的工程化切片陷阱与工具选型

Hook你是否试过把一小时口播音频丢进某款‘AI切片工具’&#xff0c;结果导出37条视频——其中12条开头卡在‘呃…’上&#xff0c;8条结尾截断在半句话里&#xff0c;还有5条字幕和画面完全不同步&#xff1f;更糟的是&#xff0c;换一批素材&#xff0c;模型表现又不稳定。这…...

水葫芦生长周期生长阶段早晚期检测数据集VOC+YOLO格式1029张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数)&#xff1a;1029标注数量(xml文件个数)&#xff1a;1029标注数量(txt文件个数)&#xff1a;1029标注类别…...