异常-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…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...