异常-java
目录
一、异常的概念和体系结构
1.1 异常的概念
1.2 异常的体系结构
1.3 异常的分类
二、异常的处理
2.1 防御式编程
2.2 异常抛出
2.3 异常捕获
2.4 异常处理流程
三、自定义异常类
一、异常的概念和体系结构
1.1 异常的概念
程序员在开发过程中,想要将代码写得尽可能完美,但在程序运行过程中,会出现一些问题,例如:数据的格式不正确、网络不畅等。在Java中,将程序执行过程中发生的不正常行为叫作异常,例如写代码时遇到的:
1. 算术异常
System.out.println(10/0);

2. 数组越界异常
int[] arr={1,2,3};
System.out.println(arr[5]);

3. 空指针异常
int[] arr=null;
System.out.println(arr.length);

Java中不同类型的异常,都有对应的类进行描述。
1.2 异常的体系结构
异常的种类有很多,为对不同类异常或错误进行更好的管理,Java内部维护一个异常体系结构。

由图可知,Throwable是异常体系最顶层的类,有Error和Exception两个子类;Error类异常是Java虚拟机无法解决的问题,例如资源耗尽等,一旦出现这类异常后面的程序就不再执行;Exception类异常是程序员可以通过代码处理的,使程序继续进行。
1.3 异常的分类
异常发生在编译期间或程序运行时,根据发生的时机不同可以分为编译时异常和运行时异常。上图中只有Runtime Exception类是运行时异常。
1. 编译时异常
编译时异常是在程序编译期间发生的异常,也叫受检查异常。
class Person{String name;public Person(String name){this.name=name;}@Overrideprotected Object clone() {return super.clone();}
}

必须捕获或声明(方法后声明)异常来方便抛出,异常最后后由JVM来处理。

2. 运行时异常
运行时异常时在程序运行期间发生的异常,也叫非受检查异常。上述所说的数组越界异常和空指针异常都是运行时异常,编译通过但运行出错。
注意:编译时期出现的语法错误不属于异常。
二、异常的处理
2.1 防御式编程
防御式编程是程序出现问题及时通知程序员进行处理,处理方式有两种:事前防御型和事后认错型。
1. 事前防御型:在操作之前就做检查。
boolean ret=false;
ret =登陆游戏();
if(!ret){
//处理游戏错误;
return;
}ret=开始匹配();
if(!ret){
//处理匹配错误;
return;
}
ret=游戏确认();
if(!ret){
//处理游戏确认错误;
return;
}
ret=选择英雄();
if(!ret){
//处理选择英雄错误;
return;
}
……
缺陷:正常流程和错误处理流程写一块,代码整体阅读性不高。
2. 事后认错型:先操作,遇到问题再处理。
try{
登陆游戏();
开始匹配();
游戏确认();
选择英雄();
……
}catch(登录游戏异常){
//处理登录游戏异常;
}catch(开始匹配异常){
//处理开始匹配异常;
}catch(游戏确认异常){
//处理游戏确认异常;
}catch(选择英雄异常){
//处理选择英雄异常;
}
……
优点:正常流程和错误流程的代码分开,代码阅读性高,容易理解代码异常处理的核心思想是事后认错型。
Java中,异常处理主要的5个关键字:throw、try、catch、final、throws。
2.2 异常抛出
在编写程序时,如果程序中出现错误,就需要将错误信息告诉给调用者。
在Java中。可以借助throw关键字,抛出一个指定的异常对象,将错误信息告诉给调用者
throw new XXXException("异常产生原因");
示例:访问数组任意位置元素的方法
public static int getEldment(int[] arr,int index){if(null==arr)throw new NullPointerException("传递的数组为空");if(index<0||index>= arr.length)throw new ArrayIndexOutOfBoundsException("数组下标越界");return arr[index];
}public static void main(String[] args) {int[] arr={1,2,3};System.out.println(getEldment(arr,3));
}

注意:throw必须写在方法体内;抛出的异常必须是Exception或Exception的子类对象;如果是Runtime Exception或者Runtime Exception的子类,则可以不用处理,交给JVM处理;如果抛出的是编译异常,用户必须处理,否则无法通过编译;异常一旦抛出,其后的代码就不会执行。
2.3 异常捕获
异常捕获是异常的具体处理方法,主要有两种:异常声明throws和try-catch捕获处理。
1. 异常声明 throws
在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理,可以借助throws将异常抛给方法的调用者来处理,即当前方法不处理异常,提醒方法的调用者处理异常。
语法格式
修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2...{
}
示例:加载指定配置文件
File file;
//FileNotFoundException:编译时异常,表明文件不存在
//没有办法处理,将错误信息报给调用者,让调用者检查文件名是否错误
public void OpenFile(String Filename) throws FileNotFoundException{if(!Filename.equals("config.ini")){throw new FileNotFoundException("配置的文件名不对");}
注意:throws必须跟在方法的参数列表之后;声明的异常必须是Exception或Exception的子类;方法内部如果抛出多个异常,throws之后就必须跟多个异常,如果抛出的多个异常,则直接声明父类即可;调用声明抛出异常的方法时,调用者必须对异常进行处理,或者使用throws抛出。
public class Config {File file;/*public void OpenFile(String FileName) throws IOException,FileNotFoundExceptionFileNotFoundException 继承于IOException*/public void OpenFile(String FileName) throws IOException{if(FileName.endsWith(".ini")){throw new IOException("该文件不是.ini文件");}if(FileName.equals("config.ini")) {throw new FileNotFoundException("配置的文件名不对");}}public static void main(String[] args) {Config config=new Config();try {config.OpenFile("config.ini");} catch (IOException e) {e.printStackTrace();}}
}
2. try-catch捕获并处理
throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行处理,就需要try-catch。
语法格式
try{
//可能出现异常的代码
}catch(捕获的异常类型 e){
//如果捕获到,就处理异常,完成后跳出try-catch结构,继续执行后面代码
}[catch(异常类型 e){
//异常处理
}finally{
//此处代码一定执行
}]
//后面代码
//当异常被捕获并处理后,后面代码一定会执行,如果捕获类型不对,后面代码就不会执行
上面代码块中[]表示可选项,可以添加也可以不添加,try中代码可能会抛出异常也可能不会。
public static void main(String[] args) {System.out.println("异常前");/*catch可以捕获多个异常,但同一时刻只能抛出一个异常*/try{System.out.println(10/0);}catch (ArithmeticException e){e.printStackTrace();//打印信息最全面System.out.println("成功捕获并处理ArithmeticException异常");//System.out.println(e.getMessage());//只打印异常信息//System.out.println(e);//打印异常类型:异常信息}catch (NullPointerException e){e.printStackTrace();System.out.println("成功捕获并处理NullPointerException异常");}System.out.println("异常后");
}

异常处理方式:根据不同的场景来决定。对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果;对于不太严重的问题(大多数场景), 可以记录错误日志, 通过监控报警程序及时通知程序员;对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试。在以上代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置。
注意:try块内抛出异常位置后的代码不会被执行;如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后结束程序----异常按照类型来捕获;
public static void main(String[] args) {try{int[] arr={1,2,3};System.out.println(arr[3]);//抛出数组越界异常}catch (NullPointerException e){//捕获空指针异常,其他类的异常无法被捕获e.printStackTrace();}System.out.println("异常处理后");
}

try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获;
public static void main(String[] args) {try{int[] arr={1,2,3};System.out.println(arr[3]);//抛出数组越界异常}catch (NullPointerException e){//捕获空指针异常,其他类的异常无法被捕获System.out.println("空指针异常");e.printStackTrace();}catch (ArrayIndexOutOfBoundsException e){//数组越界异常System.out.println("数组越界异常");e.printStackTrace();}System.out.println("异常处理后");
}

如果多个异常处理方式完全相同,也可以以如下方式写;
catch (NullPointerException|ArrayIndexOutOfBoundsException e){
}
如果异常间有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误,如下代码;
public static void main(String[] args) {try{int[] arr={1,2,3};System.out.println(arr[5]);}catch (Exception e){e.printStackTrace();}catch (NullPointerException e){e.printStackTrace();} }//Exception 'java.lang.NullPointerException' has already been caught
3. finally
写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库连接等,在程序正常或者异常退出时,必须要对资源进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。
语法格式
try{
//可能异常的代码
}catch(异常类型 e){
//处理异常
}finally{
//此处代码一定执行,不论是否异常
}
示例
public static void main(String[] args) {try{int[] arr = {1,2,3};arr[5] = 10;arr[0] = 10;}catch (ArrayIndexOutOfBoundsException e){System.out.println("处理异常");e.printStackTrace();}finally {System.out.println("finally中的代码一定会执行");}System.out.println("异常后");
}

finally 和 try-catch-finally 后的代码都会执行,那为什么还要有finally呢?
示例:在一个方法中输入一个整数并返回,在main中打印这个数
public static int getData(){Scanner sc = null;try{sc = new Scanner(System.in);int data = sc.nextInt();return data;}catch (InputMismatchException e){e.printStackTrace();}finally {System.out.println("finally中代码");}System.out.println("try-catch-finally之后代码");if(null != sc) {sc.close();}return 0;
}
public static void main(String[] args) {int date=getData();System.out.println(date);
}

上述代码,正常输入,成功接收输入后程序就返回了,try-catch-finally之后代码没有执行,即输入流没有被释放,造成资源泄漏。
注意:finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作。
public static void main(String[] args) {System.out.println(func());
}
public static int func() {try {return 5;} finally {return 10;}
}

finally 的执行是在方法返回之前(try 或者catch中若有return,会在这个return之前执行finally),但若finally中也存在return 语句, 那么就会执行finally中的return, 而不会执行try中的 return。一般不建议在finally中写return。
2.4 异常处理流程
如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递。
public static void main(String[] args) {
try {
func1();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}System.out.println("after try catch");
}
public static void func1() {
int[] arr = {1, 2, 3};
System.out.println(arr[100]);
}

异常处理流程:程序先执行 try 中的代码;如果 try 中代码异常, 就结束 try 中代码, 看与catch 中的异常类型是否匹配;如果找到匹配的异常类型, 就会执行 catch 中的代码;如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者;无论是否找到匹配的异常类型, finally 中的代码都会被执行(在该方法结束前);如果上层调用者也没有处理的了异常, 就继续向上传递;一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止。
三、自定义异常类
Java中虽然已经内置丰富的异常类, 但不能完全表示实际开发所遇到的一些异常,此时需要维护符合我们实际情况的异常结构。
例如:实现一个用户登陆功能
public class LogIn {
//用户名
private String user_name = "admin";//密码
private String user_password = "123456";//登录
public static void loginInfo(String userName, String password) {
if (!userName.equals(userName)) {
} if(!password.equals(password)) {
}System.out.println("登陆成功");
}
public static void main(String[] args) {
loginInfo("admin", "123456");
}
}
在处理用户名密码错误时可能需要抛出两种异常,我们可以基于已有的异常类进行扩展(继承), 创建和业务相关的异常类。
自定义异常类,然后继承自Exception 或者 RunTimeException;实现一个带有String类型参数的构造方法,参数含义:出现异常的原因。
public class UserNameException extends Exception{public UserNameException(String massage){super(massage);} }public class UserPasswordException extends Exception{public UserPasswordException(String massage){super(massage);} }
public class Login {//用户名private String user_name="admin";//密码private String user_password="123456";//登录public static void User_login(String user_name,String user_password) throws UserNameException,UserPasswordException{if(!user_name.equals(user_name)){throw new UserNameException("用户名错误!");}if(!user_password.equals(user_password)){throw new UserPasswordException("用户密码错误!");}System.out.println("登录成功");}public static void main(String[] args) throws UserPasswordException,UserNameException {try{User_login("admin","123456");}catch (UserNameException e){e.getStackTrace();}catch (UserPasswordException e){e.getStackTrace();}}
}
注意:自定义异常通常会继承自 Exception 或者 RuntimeException;继承自 Exception 的异常默认是受查异常;继承自 RuntimeException 的异常默认是非受查异常。
相关文章:
异常-java
目录 一、异常的概念和体系结构 1.1 异常的概念 1.2 异常的体系结构 1.3 异常的分类 二、异常的处理 2.1 防御式编程 2.2 异常抛出 2.3 异常捕获 2.4 异常处理流程 三、自定义异常类 一、异常的概念和体系结构 1.1 异常的概念 程序员在开发过程中,想要将代码写得…...
软件测试/测试开发丨Selenium Web自动化测试 高级控件交互方法
点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/27045 一、使用场景 使用场景对应事件复制粘贴键盘事件拖动元素到某个位置鼠标事件鼠标悬停鼠标事件滚动到某个元素滚动事件使用触控笔点击触控笔事件&am…...
深入Go语言:进阶指南
深入Go语言:进阶指南 欢迎来到深入Go语言的进阶指南。如果你已经熟悉Go语言的基础知识,想要更深入地探索这门语言的高级特性和技巧,那么本篇博客将为你提供有关Go语言的更多深入内容。 Go语言的并发编程 Go语言以其强大的并发支持而闻名。…...
FOXBORO FBM232 P0926GW 自动化控制模块
Foxboro FBM232 P0926GW 是 Foxboro(福克斯博罗)自动化控制系统的一部分,通常用于监测和控制工业过程。以下是关于这种类型的自动化控制模块可能具有的一些常见功能: 数字输入通道: FBM232 P0926GW 控制模块通常具有多…...
【C# Programming】编程入门:方法和参数
一、方法 1、方法的定义 由一系列以执行特定的操作或计算结果语句组成。方法总是和类关联,类型将相关的方法分为一组。 方法名称 形参和实参(parameter & argument)返回值 2、命名空间 一种分类机制,用于组合功能相关的所有类型。命名空间是分级…...
【报错】 Cannot create property ‘showColumn‘ on number ‘-1‘
1、报错原因: 代码如下: 报错是因为:this.findObject(this.option.column, "thirdId")是一个number ,没有.showColumn属性 2、修改代码 将其变成object属性就行了...
C++容器string的运用和注意
介绍 首先,先说明,string在C的string头文件中定义,而在C语言中的字符串就是字符数组,在C中,string容器相当于C语言中的字符数组,string比C语言中的字符数组更为好用,如:C中cin/cout可…...
用对工具,你的全渠道电子商务业务就成功了一半
希望将全渠道电子商务纳入您的业务战略,但不确定从哪里开始?我们为您提供保障。这篇文章将指导您了解全渠道商务的基础知识,以及它与多渠道方法的区别,还将探讨利用全渠道方法的众多好处,并讨论企业如何通过全渠道客户…...
TDengine学习(1):采集量(Metric),标签(label),数据采集点,表,超级表,子表、库
因为TDengine是面向物联网诞生的一种数据库,所以在一些概念的命名上有一点相应的特色。 一、数据采集点 比如需要对一辆高铁上的各种信息进行采集,采集信息存入数据库中。我们可以对高铁车厢内的一些数据进行采集,比如:车厢内温…...
【洛谷 P1029】[NOIP2001 普及组] 最大公约数和最小公倍数问题 题解(辗转相除法)
[NOIP2001 普及组] 最大公约数和最小公倍数问题 题目描述 输入两个正整数 x 0 , y 0 x_0, y_0 x0,y0,求出满足下列条件的 P , Q P, Q P,Q 的个数: P , Q P,Q P,Q 是正整数。 要求 P , Q P, Q P,Q 以 x 0 x_0 x0 为最大公约数,以…...
Golang 中的 errors 包详解:返回自定义 error 类型
之前的文章《Golang 中的 errors 包详解》详细讲解了 errors 包的主要类型和函数,以及它们的使用方法。本文结合之前讲解的知识,来讲解一下根据自己或团队的项目要求如何返回自定义的 error 类型。 为什么需要自定义 error 类型? 在日常开发…...
C#开发的OpenRA游戏之信标按钮
前面已经分析了两个按钮:变卖和维修,接着下来就是分析信标按钮,这个按钮使用是比较少,但是对于多人游戏时,使用这个信号就很方便同盟军过来查看和帮助了,相当于一个朋友之间共同查看的地址。当你经过同盟标记的标志时,就会听到beacon detected,检测到信标,这就是你的盟…...
16字节协议的串口通信
1.协议要求 协议为帧传输,一共16字节。主要是2字节的固定帧头 EB 90,2字节的帧计数(用来计数发出的帧),10字节的数据和2字节的校验位 帧头:2字节,固定值 8’HEB、8’H90 帧计数:2字节,用来说明发出去帧是…...
升哲科技城市级“算力+数字底座”服务亮相2023服贸会
9月2日至6日,以“开放引领发展,合作共赢未来”为主题的2023年中国国际服务贸易交易会在北京隆重举办。作为城市级数据服务商,升哲科技(SENSORO)连续第四年参加服贸会,携城市级“算力数字底座”服务及在城市…...
动态规划之简单多状态
简单多状态 1. 按摩师(easy)2. 打家劫舍II (medium)3. 删除并获得点数(medium)4. 买卖股票的最佳时机含冷冻期(medium)5. 买卖股票的最佳时机III(hard) 1. 按…...
跨数据中心Multi-Fabric解决方案:L2和L3网络的高效连接和扩展
云数据中心里,为什么需要DCI互通? 云化数据中心,网络资源通过虚拟化技术形成资源池,实现业务与物理网络解耦,通过网络虚拟化,物理网络资源可以被分成多个虚拟网络资源,从而提高网络资源的使用效…...
upload-labs靶场通关详解
文章目录 Pass-01Pass-02Pass-03Pass-04Pass-05Pass-06Pass-07Pass-08Pass-09Pass-10Pass-11Pass-12Pass-13Pass-14Pass-15Pass-16Pass-17Pass-18Pass-19Pass-20方法一(文件夹名欺骗绕过)方法二(%00截断攻击) Pass-21 Pass-01 绕过…...
Leetcode刷题笔记--Hot41-50
1--二叉树的层序遍历(102) 主要思路: 经典广度优先搜索,基于队列; 对于本题需要将同一层的节点放在一个数组中,因此遍历的时候需要用一个变量 nums 来记录当前层的节点数,即 nums 等于队列元素的…...
「MySQL-02」数据库的操纵、备份、还原和编码规则
目录 一、库操作 1. 创建数据库 2. 查看所有数据库 3. 删除数据库 4. 修改数据库 5. 进入一个数据库 二、查看和设置数据库的编码规则 1. MySQL的两个编码规则:字符集和校验规则 2. 查看MySQL当前使用的字符集以及校验规则 3. 查看MySQL支持的所有字符集 4. 查看MyS…...
Effective C++条款24——若所有参数皆需类型转换,请为此采用non-member涵数(设计与声明)
我在导读中提过,令classes支持隐式类型转换通常是个糟糕的主意。当然这条规则有其例外,最常见的例外是在建立数值类型时。假设你设计一个class用来表现有理数,允许整数“隐式转换”为有理数似乎颇为合理。的确,它并不比C内置从int…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
