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 的执行顺序和返回值问题,其中 finally 一定会执行,但是为什么会这样? 下面看下 try-catch-finally 背后的实现原理 try-catch public class Test {public static void main(String[] args)…...

基于双层优化的微电网系统规划设计方法(Matlab代码实现)
目录 💥1 概述 1.1 微电网系统结构 1.2 微电网系统双层规划设计结构 1.3 双层优化模型 1.4 上层容量优化模型 1.5 下层调度优化模型 📚2 运行结果 🎉3 文献来源 🌈4 Matlab代码、数据、文章讲解 💥1 概述 文献来源&…...

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

2023年华数杯数学建模C题思路分析
文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 0 赛题思路 (赛题出来以后第一时间在CSDN分享) 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格式的数据,所以,需要将数据集格式调整为 datasets|images|train|00000…...

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

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

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

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

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

常压室温超导材料:揭开物理学的新篇章
常压室温超导材料:揭开物理学的新篇章 目录 引言超导现象简介常压室温超导材料的重要性常压室温超导材料的研究进展常压室温超导材料的挑战与前景结论 1. 引言 自从1911年荷兰物理学家海克卡默林奥涅斯发现超导现象以来,超导技术在许多领域都有着广泛…...
【《C# 10 和 .NET 6入门与跨平台开发(第6版)》——一本循序渐进的C#指南】
这个新版本对上一版做了全面修订,涵盖C# 10和.NET 6的所有新功能. 本书讨论面向对象编程、编写函数、测试函数、调试函数、实现接口以及继承类等主题;介绍.NET API,这些API可执行多种任务,如管理和查询数据,监视和改进…...

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

第六篇-ChatGLM2-6B-CentOS7安装部署-GPU版
环境 系统:CentOS-7 CPU: 14C28T 显卡: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
此类为扩展注入类,使用autofuc 仅供参考 注入接口和实现。 使用方法: //配置项调用ConfigContainer public void ConfigureContainer(ContainerBuilder builder){TestMicroService.ConfigContainer(builder);} //service调用RegisteApiController …...

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

正则表达式中的大括号-花括号{}有什么用?
在正则表达式中,花括号 {} 是用于指定匹配次数的量词元字符。它可以用来表示匹配的次数范围或精确匹配次数。 具体来说,花括号 {m} 表示前面的模式匹配恰好出现 m 次,而 {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. 状态栏的…...

Packet Tracer - 连接有线和无线 LAN
Packet Tracer - 连接有线和无线 LAN 地址分配表 设备 接口 IP 地址 连接到 云 Eth6 N/A Fa0/0 Coax7 N/A Port0 电缆调制解调器 Port0 N/A Coax7 Port1 N/A 互联网 Router0 控制台端口 N/A RS232 Fa0/0 192.168.2.1/24 Eth6 Fa0/1 10.0.0.1/24 Fa…...

02 笔记本电脑m.2硬盘更换
1 工具展示 SN570的2T硬盘。够用了。 对于这台华为,使用的螺丝刀批头是4或5毫米的六边形批头。如果出现打滑的情况,请不要用蛮力哦。 2 更换过程 使用螺丝刀拧走后盖的螺丝(为了避免会出问题要再次打开,我到现在还没有把螺丝拧回…...

2.04 商品搜索功能实现
根据关键字获取分类查询对应的分页商品信息,并可以价格和销量进行排序切换 步骤1:mapper.xml编写sql语句 <!-- k: 默认,代表默认排序,根据name--> <!-- c: 根据销量排序--> <!-- p: 根据价格排序--> <sel…...

【SEO基础】百度权重是什么意思及网站关键词应该怎么选?
百度权重是什么意思及网站关键词应该怎么选? 正文共:3253字 20图 预计阅读时间:9分钟 1.什么是网站权重? 这段时间和一些朋友聊到网站权重以及关键词,发现蛮多人对于这两个概念的认知还是存在一些错误的…...

Unity实现在3D模型标记
Canvas 模式是UI与3D混合模式(Render modelScreen space-Camera) 实现在3D模型标记,旋转跟随是UI不在3D物体下 代码: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public clas…...

iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动
iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动 在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。 在…...

性能调试【学习笔记】
什么是调优? 每执行一个Java命令,就分配一个JVM,调优时不要混淆。 根据需求进行JVM规划和预调优优化运行JVM的运行环境(慢、卡顿)解决JVM运行过程中出现的各种问题(内存泄露、内存溢出OOM) 生…...

【taro react】---- 获取元素的位置和宽高等信息
1. 需求分析 添加节点的布局位置的查询请求。相对于显示区域,以像素为单位。其功能类似于 DOM 的 getBoundingClientRect。返回 NodesRef 对应的 SelectorQuery。区分小程序和H5的环境,调用 getBoundingClientRect 获取对应的信息。 2. H5 实现 判断传…...

Java【Spring】项目创建、存储和获取 Bean 的基本方式
文章目录 前言一、创建 Spring 项目1, 创建 Maven 项目2, 添加 Spring 依赖3, 创建启动类 二、存储 Bean 的基本方式1, 创建 Bean2, 存储 Bean 三、获取 Bean 的基本方式1, 获取上下文对象2, 获取 Bean3, 使用 Bean 总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的…...

docker minio安装
1.介绍 Minio是一款开源的对象存储服务,它可以在任何硬件或云平台上提供高性能、高可用性和高安全性的存储解决方案。Minio最新版是2021年11月发布的RELEASE.2021-11-24T23-19-33Z,它带来了以下几个方面的改进和新特性: - 支持S3 Select AP…...