【Java】异常处理见解,了解,进阶到熟练掌握

各位看官早安午安晚安呀

如果您觉得这篇文章对您有帮助的话

欢迎您一键三连,小编尽全力做到更好
欢迎您分享给更多人哦

大家好我们今天来学习Java面向对象的的抽象类和接口,我们大家庭已经来啦~

目录

1.(throws和throw)我们不管这个异常,把这个异常抛出去

1.1:throws的注意事项

1.2:throw的注意事项

2:(try-catch)我们主动地去捕捉这个异常

2.1. try块内抛出异常位置之后的代码将不会被执行

2.2. 如果抛出异常类型与catch时异常类型不匹配

2.3. try中可能会抛出多个不同的异常对象

2.4:我们也可以有以下两种不推荐的捕获方式

3:关于 "调用栈"(e.printStackTrace())

关于 "调用栈"

4:finally

4:自定义异常类


Java 中,将程序执行过程中发生的不正常行为称为异常
要认识异常首先我们要认识一张图
从上图中可以看到:
1. Throwable 是异常体系的顶层类,其派生出两个重要的子类 , Error Exception
2. Error 指的是 Java 虚拟机无法解决的严重问题,比如: JVM 的内部错误、资源耗尽等 ,典型代表:
StackOverflowError OutOfMemoryError ,一旦发生回力乏术。
3. Exception 异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说的异常就是Exception
异常大概处理方案:

关于异常的一般处理方式:

异常的种类有很多, 我们要根据不同的业务场景来决定.
对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果
对于不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿
对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试
在我们当前的代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置. 以后在实际工作中我们会采取更完备的方式来记录异常信息
比如我们之前写代码时经常遇到的:
1: 算数异常
   System.out.println(10/0);
2.   数组越界异常
int [] arr = { 1 , 2 , 3 };
System . out . println ( arr [ 100 ]);
3:空指针异常
        int [] array = null;System.out.println(array.length);

这些异常,我们写代码的时候不会显示异常,但是程序运行时就会报错;

(这种异常我们称之为运行时异常也叫非受查异常

既然有非受查异常,就自然会有受查异常

譬如:我们之前一直没明白的克隆方法,我们子类要用这个克隆方法,克隆之后肯定要用一个新的对象来接收,那就是Person person2 = person1.clone();但是clone()是Object类的方法,我们只能在类里通过super调用,所以子类要用就必须要重写这个方法。

但是重写之后还是会报异常CloneNotSupportedException

我们只要调用这个方法就会报异常,但是我们还是要用到这个方法

所以说现在摆在我们面前的有两条路:

1.我们不管这个异常,把这个异常抛出去

2:我们主动地去捕捉这个异常

1.(throws和throw)我们不管这个异常,把这个异常抛出去

抛出去这个异常就要引出一个关键字throws了

然后还有一个关键字throw和它很像(这个关键字也是抛出一个异常)

他俩的区别在于:

throws是抛出已经出现的异常(一般放在方法参数列表之后)(也算是处理了,但不算是真正的处理,只是异常报告给抛出异常方法的调用者,由调用者处理

而throw是我们主动去抛出一个异常,一般是程序没出现我们为了提醒别人而抛出的异常

但是这个异常迟早是要被捕捉的,不然异常一直存在,最后大家都处理,只能交给JVM去处理,最后程序就只能报出来这个异常

我们throws出去这个异常

大家可以看到这个时候就不报异常了,但是我们现在调用它试试呢?

现在它又报错了,为啥呢?就像我上面所说的你只是抛出了这个异常(暂时解决了这个问题)实际上是把问题抛给了这个方法的调用者

然后我们还不想解决,那就,让main函数也把这个责任甩出去

按理说程序运行时,JVM会处理这个异常

但是我们实现了一个克隆接口(允许)该类的对象被拷贝

Cloneable接口是一个标记接口(即它没有任何方法定义)。当一个类实现了Cloneable接口,这表示这个类的对象支持克隆操作,而且Person类实现了Cloneable接口并且正确地重写了clone()方法,所以说最终没有抛出这个异常

1.1:throws的注意事项

处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助 throws 将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常
注意:
1. throws 必须跟在方法的参数列表之后
2. 声明的异常必须是 Exception 或者 Exception 的子类
3. 方法内部如果抛出了多个异常, throws 之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可。
 
publicstaticvoidmain(String[]args)throwsArrayIndexOutOfBoundsException,ArithmeticException{}
可以替换成
public static void main(String[] args) throws Exception{
}

4:调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用 throws 抛出
(我们讲述的clone方法和main方法)
5: 将光标放在抛出异常方法上,ALT点击+enter快速处理

1.2:throw的注意事项

1.throw 必须写在方法体内部
2. 抛出的对象必须是 Exception 或者 Exception 的子类对象
3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给 JVM 来处理
4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
throws继续抛出或者try-catch处理,最后try-catch不处理的话JVM处理,程序异常终止
5. 异常一旦抛出,其后的代码就不会执行

2:(try-catch)我们主动地去捕捉这个异常

就像如果我们捕捉了上面的克隆异常(但是他是一个异常,还是不会被执行,所以我们最好还是实现一个克隆接口,最终别抛出异常)

如果我们要捕捉异常

这时候就要引出一个组合了 try-catch捕获并处理(细节我们一会会具体将到)

try {
// 将可能出现异常的代码放在这里
} catch ( 要捕获的异常类型 e ){
// 如果 try 中的代码抛出异常了,此处 catch 捕获时异常类型与 try 中抛出的异常类型一致时 ,或者是try中抛出异常的基类时,就会被捕获到
// 对异常就可以正常处理,处理完成后,跳出 try-catch 结构,继续执行后序代码
} finally {
// 此处的语句无论是否发生异常,都会被执行到
}
// 如果没有抛出异常,或者异常被捕获处理了,这里的代码也会执行

示例:

2.1. try块内抛出异常位置之后的代码将不会被执行

 public static void main(String[] args){try{System.out.println(10/0);System.out.println("想你");}catch(ArithmeticException e){System.out.println("捕捉到了算数异常");}}

这里我们捕捉到了算数异常,但是“想你”并没有被打印这是因为这里程序运行到这里已经发现了异常,就会去捕捉(因为我们用try-catch组合了)所以后面的代码就不会被执行了

就像程序这里(哈哈打印了,想你没有打印)

2.2. 如果抛出异常类型与catch时异常类型不匹配

即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM收到后中断程序----异常是按照类型来捕获的

public static void main(String[] args){try{System.out.println(10/0);System.out.println("想你");}catch(NullPointerException e){System.out.println("捕捉到了算数异常");}System.out.println("想你");}

一个想你都没有打印

2.3. try中可能会抛出多个不同的异常对象

则必须用多个catch来捕获----即多种异常,多次捕获 ,并且捕获到了一个异常,就不会进入另一个catch了

  public static void main(String[] args){try{System.out.println(10/0);int[] arr = {1, 2, 3};System.out.println(arr[100]);}catch(NullPointerException e){System.out.println("捕获到了空指针异常");}catch(ArithmeticException e){System.out.println("捕捉到了算数异常");}System.out.println("想你");}

这时候就有小伙伴问了,那另一个异常去哪了?

其实我们上面就已经讲述过了,一个异常出现,我们用try-catch捕获处理(这个异常下面的代码就不会执行了,直接执行捕获后的catch里面的代码,以及处理完程序后面的代码)

2.4:我们也可以有以下两种不推荐的捕获方式

1.

catch ( ArrayIndexOutOfBoundsException | NullPointerException e ) {
...
}
不过我们不推荐这种方式:太模糊了,到底是哪种异常
2.一次性捕获所有异常:
catch( Exception e ){    这是异常的父类
}
注意: 如果异常之间具有父子关系,一定是子类异常在前 catch ,父类异常在后 catch ,否则语法错误:(否则,相当于,你在前面就把水全部堵住了,异常根本流过来)
子类异常在前 catch ,父类异常在后 catch(还是有点作用的,防止程序异常终止嘛)

3:关于 "调用栈"(e.printStackTrace()

关于 "调用栈"

方法之间是存在相互调用关系的, 这种调用关系我们可以用 "调用栈" 来描述. 在 JVM 中有一块内存空间称为 "虚拟机栈" 专门存储方法之间的调用关系. 当代码中出现异常的时候, 我们就可以使用 e.printStackTrace(); 的方式查看出现异常代码的调用栈.

譬如上述代码:

 public static void main(String[] args){try{System.out.println(10/0);int[] arr = {1, 2, 3};System.out.println(arr[100]);}catch(NullPointerException e){System.out.println("捕获到了空指针异常");}catch(ArithmeticException e){System.out.println("捕捉到了算数异常");e.printStackTrace();}System.out.println("想你");}

4:finally

在写程序时, 有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源 :网络连接、数据库 连接,IO 流等, 在程序正常或者异常退出时,必须要对资源进进行回收
另外,因为 异常会引发程序的跳转,可能 导致有些语句执行不到 finally 就是用来解决这个问题的。
 public static void main(String[] args){try {System.out.println(10 / 0);int[] arr = {1, 2, 3};System.out.println(arr[100]);}catch (ArrayIndexOutOfBoundsException e){System.out.println("捕获到了数组越界异常");}finally {System.out.println("不管是否捕获到了异常,finally后面的都会被执行");}System.out.println("想你");}

就是想你没有被执行(finally就是用来处理善后工作的)

譬如关闭输入流

大家可以想想如果没有finally,这个程序刚才没有捕捉到异常,就异常终止了,但是输入流没有没关闭(这时候就造成了资源的泄露)

注意:一般我们不建议在 finally 中写 return (被编译器当做一个警告).

public static void main(String[] args) {
System.out.println(func());
}
public static int func() {
try {
return 10;
} finally {
return 20;
}
}
A: 10 B: 20 C: 30 D: 编译失败

选择B

finally 执行的时机是在方法返回之前 (try 或者 catch 中如果有 return 会在这个 return 之前执行 finally).
但是如果
finally 中也存在 return 语句 , 那么就会执行 finally 中的 return, 从而不会执行到 try 中原有的 return.
一般我们不建议在 finally 中写 return ( 被编译器当做一个警告 )
所以说我们这两个问题大家清楚了吗?
1. throw throws 的区别?
2. finally 中的语句一定会执行吗?
异常处理流程总结
程序先执行 try 中的代码
如果 try 中的代码出现异常 , 就会结束 try 中的代码 , 看和 catch 中的异常类型是否匹配 .
如果找到匹配的异常类型 , 就会执行 catch 中的代码
如果没有找到匹配的异常类型 , 就会将异常向上传递到上层调用者
.
无论是否找到匹配的异常类型 , finally 中的代码都会被执行到 ( 在该方法结束之前执行 ).
如果上层调用者也没有处理的了异常 , 就继续向上传递 .
一直到 main 方法也没有合适的代码处理异常 , 就会交给 JVM 来进行处理 , 此时程序就会异常终止 .

4:自定义异常类

接下来我们实现一个登录系统

public class LogIn {private String userName = "admin";private String password = "123456";public void loginInfo(String userName, String password) {if (!this.userName.equals(userName)) {System.out.println("名字错误");return;}if (!this.password.equals(password)) {System.out.println("密码错误");return;}System.out.println("登陆成功");}public static void main(String[] args) {LogIn logIn = new LogIn();logIn.loginInfo("admin", "1234561");}
}

但是总是sout输出太俗了,不能有效的提醒,这个时候我们就可以自定义一个异常类

但是我们应该如何定义一个异常类呢?(并且运行时能给我们检测出来)我们不妨看看其他异常类是怎么定义的?譬如:算数异常

那么我们也这样写两个异常

然后我们的代码就可以改成这个样子

public class LogIn {private String userName = "admin";private String password = "123456";public void loginInfo(String userName, String password) throws UserNameException,UserPasswordException {if (!this.userName.equals(userName)) {throw new UserNameException("用户名错误");}if (!this.password.equals(password)) {throw new UserPasswordException("登录密码错误");}System.out.println("登陆成功");}public static void main(String[] args) {LogIn logIn = new LogIn();try{logIn.loginInfo("admin", "1234561");}catch(UserNameException e){System.out.println("");}}
}

登录密码错误

其实定义方式就是这个

1. 自定义异常类,然后继承自 Exception 或者 RunTimeException
2. 实现一个带有 String 类型参数的构造方法,参数含义:出现异常的原因

注意继承Exception时是编译异常 ,继承RunTimeException是受查时异常

所以说,继承RunTimeException时就不需要抛出异常了(写代码时也不会报异常),如果我们不处理,运行时JVM会帮我们处理(最后返回发生异常的位置)

大家可以看一下如果我继承Exception时不抛出异常,这个时候就会报错,因为继承Exception是编译时异常(受查异常)

总之,大家根据自己的需求去选择是用编译时异常还是运行时异常就好了

上述就是 Java异常处理了解,熟悉到进阶的全部内容了,能看到这里相信您一定对小编的文章有了一定的认可,异常的出现,让我们对于程序有了更多的认识~~~

有什么问题欢迎各位大佬指出
欢迎各位大佬评论区留言修正

您的支持就是我最大的动力​​​!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/59297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Django REST framework构建RESTful API

使用Django REST framework构建RESTful API Django REST framework简介 安装Django REST framework 创建Django项目 创建Django应用 配置Django项目 创建模型 迁移数据库 创建序列化器 创建视图 配置URL 配置全局URL 配置认证和权限 测试API 使用Postman测试API 分页 过滤和排序…

022集——统计多条线的总长度(CAD—C#二次开发入门)

如下图所示,选择多条线并统计长度: c#中不包含直接获取curve曲线长度 属性,需用如下方法:curve.GetDistanceAtParameter(item.EndParam) 附部分代码如下: using Autodesk.AutoCAD.ApplicationServices; using Autode…

W5100S-EVB-Pico2评估板介绍

目录 1 简介 2 硬件资源 2.1 硬件规格 2.2 引脚定义 2.3 工作条件 3 参考资料 3.1 RP2350数据手册 3.2 W5100S数据手册 3.3 原理图 原理图 & 物料清单 & Gerber 文件 3.4 尺寸图(单位:mm) 3.5 参考例程 认证 CE FCC …

【Python】自然语言处理神器:NLTK库初探与文本处理案例

自然语言处理神器:NLTK库初探与文本处理案例 在自然语言处理(NLP)领域,Python 的 NLTK(Natural Language Toolkit,自然语言工具包)被广泛认为是入门级和应用级的强大工具之一。无论是处理文本、…

STM32F103C8T6学习笔记4--模拟旋转编码器的按键中断

1、实验内容 通过旋转编码器正反转来计数,由对应的GPIO产生中断。但是我在Proteus里面没有找到相关的EC11旋转编码器元件,暂时通过电路模拟的方式实现。 S1按下引脚PB0产生低电平信号,触发中断,计数值减一。 S2按下引脚PB1产生低…

宝顶白芽,慢生活的味觉盛宴

在快节奏的生活中,人们愈发向往那种悠然自得、返璞归真的生活方式。白茶,以其独特的韵味和清雅的风格,成为了现代人追求心灵宁静与生活品质的象征。而在众多白茶之中,竹叶青茶业出品的宝顶白芽以其甘甜醇爽的特质,成为…

23.智能停车计费系统(基于springboot和vue的Java项目)

目录 1.系统的受众说明 2 相关概念和技术介绍 2.1 JAVA技术介绍 2.2 SpringBoot框架 2.3B/S架构 2.4 MySQL数据库 3 系统需求分析 3.1 问题定义 3.2 可行性分析 3.3系统用例分析 3.4 系统流程分析 3.4.1 登录流程 3.4.2 添加信息流程 3.4.3 删除信息流程 4…

Chrome 130 版本开发者工具(DevTools)更新内容

Chrome 130 版本开发者工具(DevTools)更新内容 一、网络(Network)面板更新 1. 重新定义网络过滤器 网络面板获新增了一些过滤条件,这些过滤条件是根据反馈重新设计的,特定于类型的过滤条件保持不变&…

清华双臂机器人扩散大模型RDT:先预训练后微调,支持语言、图像、动作多种输入(1B参数)

前言 通过上文介绍的GR2,我们看到了视频生成模型在机器人训练中的应用 无独有偶,和GR2差不多一个时期出来的清华RDT,其模型架构便基于视频生成架构DiT改造而成(当然,该清华团队其实也在DiT之前推出了U-ViT,具体下文会…

万彪离职,荣耀CEO赵明豪赌AI手机胜算几何?

"荣耀新的远方在哪里?" 作者 | 米 卢 编辑 | 卢旭成 10月30日晚,荣耀在深圳国际会展中心发布了AI旗舰手机mogic7系列,这意味着终于能真正独立操盘荣耀的CEO赵明,开始压上全部身家,豪赌AI手机。 赵明说&…

SpringBoot在线教育系统:集成第三方服务

5系统详细实现 5.1 普通管理员管理 管理员可以对普通管理员账号信息进行添加修改删除操作。具体界面的展示如图5.1所示。 图5.1 普通管理员管理界面 5.2 课程管理员管理 管理员可以对课程管理员进行添加修改删除操作。具体界面如图5.2所示。 图5.2 课程管理员管理界面 5.3 …

六、Go语言快速入门之数组和切片

文章目录 数组和切片数组:one: 数组初始化:two: 数组的遍历:three: 多维数组:four: 将数组传递给函数 切片(Slice):one: 切片的初始化:star: new和make区别 :two: 切片的使用:three: 将切片传递给函数:four: 多维切片:four: Bytes包:four: 切片和垃圾回收 📅 2024年…

HFSS 3D Layout中Design setting各个选项的解释

从HFSS 3D LAYOUT菜单中,选择Design Settings打开窗口,会有六个选项:DC Extrapolation, Nexxim Options, Export S Parameters, Lossy Dielectrics, HFSS Meshing Method, and HFSS Adaptive Mesh. DC Extrapolation 直流外推 直流外推分为标…

大模型备案安全评估报告编写说明

一、语料安全评估 (一)评估内容 1.文本训练语料规模 训练语料存储规模,按文本格式存储时的语料大小。 训练语料数量,按词元(Token)计数。 2.各类型语料规模 训练语料中的中文文本、英文文本、代码、图片、音频、视频及其他语料的规模。 3.训练语料…

ElementUI<el-table></el-table>表格中固定列横向滚动条无法拖动解决

当表格有固定列会出现横向滚动条无法拖动问题,尤其是固定列固定在左边且表格没数据的时候。这可能是因为固定区域盖住了横向滚动条,不是视觉上的覆盖,是去拖动时没有触发效果。 解决方法如下: 1.修改层级 使用z-index&#xff0…

ctfshow web系列

声明: 本文章只适用于网络安全交流与学习,请读者遵循网络安全法,若读者从事一些与网络安全不相关的事情,结果均与本人无关!!! 是ctfshow的web题:https://www.ctf.show/ web3: 开局提示使用php include get url include()函数是…

善用Git LFS来降低模型文件对磁盘的占用

将讲一个实际的例子:对于模型文件,动辄就是好几个G,而有的仓库更是高达几十G,拉一个仓库到本地,稍不注意直接磁盘拉满都有可能。 比如:meta-llama-3.1-8b-instruct,拉到本地后发现居然占用了60G…

十四届蓝桥杯STEMA考试Python真题试卷第二套第五题

来源:十四届蓝桥杯STEMA考试Python真题试卷第二套编程第五题 本题属于迷宫类问题,适合用DFS算法解决,解析中给出了Python中 map() 和列表推导式的应用技巧。最后介绍了DFS算法的两种常见实现方式——递归实现、栈实现,应用场景——迷宫类问题、图的连通性、树的遍历、拓朴排…

MYSQL安装(ubuntu系统)

rpm -qa 查询安装软件包 ps axj 查询服务 卸载mysql(万不得已) ps axj | grep mysql 查看是否存在mysql服务 systemctl stop mysqld 关闭该服务 rpm -qa | grep mysql 查安装mysql安装包 rmp -qa | grep mysql | xargs (yum apt) -y remove进行批量…

智能提醒助理系列-jdk8升级到21,springboot2.3升级到3.3

本系列文章记录“智能提醒助理”产品建设历程,记录实践经验、巩固知识点、锻炼总结能力。 本篇介绍技术栈升级的过程,遇到的问题和解决方案。 一、需求出发点 智能提醒小程序 当前使用的是jdk8,springboot2.3,升级到jdk21和springboot3.3 学…