⛵ ⛵ ⛵ ⛵ ⛵ 🚀 🚀 🚀 🚀 🚀
大家好🤝,我是 👉老孙👈,未来学习路上多多关照 🤝 一个喜欢用 ✍️ 博客记录人生的程序猿 🙉,或许这是一件很有意义又有趣的事 📖 ⏰ 🌏
🔥 🔥 🔥 🔥 🔥 ⭐ ⭐ ⭐ ⭐ ⭐
Java异常目录
- 1、思维导图
- 2、异常概述
- 3、异常处理机制
- 4、捕获异常 try-catch-finally
- 4.1、try-catch-finally 使用说明
- 4.2、处理运行时异常
- 4.3、处理编译时异常
- 5、声明抛出异常 throws
- 6、抛出和捕获结合使用
- 7、自定义异常 throw
Java学习笔记前期内容回顾 |
---|
Java学习笔记【1】Java概述 |
Java学习笔记【2】JDK环境配置 |
Java学习笔记【3】第一个 Java 程序Hello World! |
Java学习笔记【4】基础语法 - - 关键字、变量和数据类型、Scanner类 |
Java学习笔记【5】基础语法 - - 运算符 和 运算规则 |
Java学习笔记【6】基础语法 - - 数组、流程控制和进制 |
待更新… |
1、思维导图
2、异常概述
异常:在Java语言中,将程序执行中发生的不正常情况称为异常 (开发过程中的语法错误和逻辑错误不是异常)。
异常分类:
- Error:Java虚拟机无法解决的严重问题,一般不编写针对性的代码进行处理。
- 如:JVM系统内部错误、资源耗尽等严重情况、StackOverflowError堆栈溢出等
- Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:空指针异常、试图读取不存在的文件、数组角标越界…
- 编译时异常:是指编译器要求必须处置的异常,即程序在运行时由于外界因素造成的一般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。对于这类异常,如果程序不处理,可能会带来意想不到的结果。
- 运行时异常:是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。java.lang.RuntimeException 类及它的子类都是运行时异常。比如:除数为0,数组下标越界等;对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
对于异常一般有两种解决方法:
- 终止程序的运行
- 编写程序时就考虑到错误的检测、错误消息的提示,以及错误的处理:捕获异常、声明抛出异常、自定义异常
Java异常处理机制:捕获异常、声明抛出异常
3、异常处理机制
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。
Java异常处理Java采用的异常处理机制,是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护。
异常处理的2种方式:
- 方式一:try-catch-finally(直接捕获处理掉)
- 方式二:throws + 异常类型(抛出交给调用者处理)
Java提供的是异常处理:抓抛模型
- 过程一:“抛”
- 程序在执行过程中如果出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出(throw);一旦抛出对象以后,其后的代码就不再执行。
- 关于异常对象的产生:
- 系统自动生成的异常对象
- 手动的生成一个异常对象,并抛出(throw)
- 过程二:“抓”
- 可以理解为异常的处理方式:① try-catch-finally ② throws
4、捕获异常 try-catch-finally
捕获异常过程:在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型去catch中进行匹配。一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。如果有finally的情况下先执行finally中的语句,然后继续执行其后的代码。
4.1、try-catch-finally 使用说明
try{…}语句块:
- 捕获异常的第一步将可能出现异常的代码放在try语句块中
- 在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配。
在catch语句块中是对异常对象进行处理的代码
- 每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
- 如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。比如: 可以用 ArithmeticException 类 作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。
- catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
- catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面;否则报错。
finally语句块:是可选的
- 一定会执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
- 像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。
try{
...... // 可能产生异常的代码
}
catch( 异常类型1 变量名1 ){
...... // 当产生异常类型1时的处置措施
}
catch( 异常类型2 变量名1 ){
...... // 当产生异常类型2时的处置措施
}
...
finally{
...... //无论是否发生异常,一定会执行的代码【可选】
}
// 获取异常信息,返回字符串
System.out.println(e.getMessage());
// 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
e.printStackTrace();
4.2、处理运行时异常
处理运行时异常 RuntimeException
- 常见运行时异常有:数学运算异常(如0位除数)、类型转换异常、空指针异常、数字格式异常、数组或字符下标越界异常等
- 这些类的异常的特点是:即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过(但运行时会发生异常使得程序运行终止)
- 开发中,由于运行时异常比较 常见,所以我们 通常就不针对运行时异常编写try-catch-finally。
public class IndexOutException {
public static void main(String[] args) {
String[] arr = {"aaa", "bbb", "ccc"};
try {
System.out.println(arr[3]);
System.out.println("try...");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组角标越界!");
}
System.out.println("方法执行结束...");
}
}
4.3、处理编译时异常
处理编译时异常:则必须捕获,否则编译错误。
- 常见编译时异常有:IO异常、数据库访问异常、指定类不存在异常等
- 使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现,转化为运行时异常。
- try-catch-finally结构可以嵌套
// 将工程路径下的test.txt文件打印到控制台
public class IOExceptionTest {
public static void main(String[] args) {
try {
FileInputStream in = new FileInputStream("test.txt");
int len;
len = in.read();
while (len != -1) {
System.out.print((char) len);
len = in.read();
}
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println(e);
} finally {
System.out.println("执行其它语句...");
}
}
}
public void testDelete() {
Connection conn = null;
Statement statement = null;
try {
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取连接对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
// 获取执行sql语句的对象
statement = conn.createStatement();
// sql语句
String sql = "delete from student where id = 6";
// 发送sql
int i = statement.executeUpdate(sql);
System.out.println("受影响的条数:" + i);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭连接
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
5、声明抛出异常 throws
如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。(由JVM来处理,即默认异常操作,将会在出现异常处,终止程序运行,并返回异常栈内信息)
在方法声明中用throws语句可以声明抛出异常的列表(可以声明多个的异常),throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
public void method(String str) throws 异常A,异常B,... { 方法体 }
throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
public void readFile(String file) throws FileNotFoundException{
...
// 读文件的操作可能产生FileNotFoundException类型的异常
FileInputStream fis = new FileInputStream(file);
...
}
public void readFile(String file) throws IOException {
...
FileInputStream fis = new FileInputStream(file);
...
}
重写方法不能抛出比被重写、方法范围更大的异常类型。
- 在多态的情况下, 一般对methodA()方法的调用异常的捕获按父类声明的异常处理。
public class A {
public void methodA() throws IOException {...}
}
public class B1 extends A {
public void methodA() throws FileNotFoundException {...}
}
public class B2 extends A {
//报错
public void methodA() throws Exception {...}
}
6、抛出和捕获结合使用
为保证程序正常执行,代码必须对可能出现的异常进行处理,需要 try-catch-finally 和 throws 结合使用。
注意:异常抛出给调用者,最终需在main()方法中处理。
举例:将工程路径下的test.txt文件打印到控制台
public class IOExceptionThrows {
public static void main(String[] args) {
IOExceptionThrows readFileTest = new IOExceptionThrows();
try {
readFileTest.readFile();
} catch (IOException e) {
e.printStackTrace();
}
}
// 抛出readFile()产生的异常,交给调用者main()处理
public void readFile() throws IOException {
FileInputStream in = new FileInputStream("test.txt");
int b = in.read();
while (b != -1) {
System.out.print((char) b);
b = in.read();
}
in.close();
}
}
// 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。
IOException e = new IOException();
throw e;
// 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误:
throw new String("want to throw");
7、自定义异常 throw
JDK中定义了大量的异常可以描述异常情况,但在开发中会出现特殊的问题,为了解决这个问题,Java允许用户自定义异常;抛出异常 thow:当程序查到一个错误后,创建一个适当类型异常的实例并抛出它。
- 一般地,用户自定义异常类都是RuntimeException的子类
- 如何自定义异常类:需要编写几个重载的构造器、提供serialVersionUID、继承于现有的异常结构。
- 用户自己的异常类 必须继承Throwable类或其子类的实例
- 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
// 举例:人数注册
public class MyExceptionTest {
public void register(int num) throws MyException {
if (num < 0) {
//出现异常时:创建自定义的异常类的实例
throw new MyException("人数为负值,不合理", 500);
} else {
System.out.println("登记成功,人数为" + num);
}
}
public void manager() {
try {
register(-1);
} catch (MyException e) {
System.out.println("登记失败,出错类型" + e.getId() + "\n" + e.getMessage());
}
System.out.print("本次登记操作结束");
}
public static void main(String args[]) {
MyExceptionTest t = new MyExceptionTest();
t.manager();
}
}
// 自定义异常类
public class MyException extends Exception {
static final long serialVersionUID = 13465653435L;
private int id;
public MyException(String message, int id) {
super(message);
this.id = id;
}
public int getId() {
return id;
}
}
在开发中自定义异常类一般继承异常类后重新一下构造方法即可,然后交给全局异常处理器。
// 举例:springboot项目实现用户下单的业务
@Transactional
public void submit(Orders orders) {
...
// 防止购物车为空时点击下单
if (shoppingCarts == null || shoppingCarts.size() == 0) {
throw new CustomException("购物车为空,不能下单!");
}
...
}
// 自定义异常类:CustomException
public class CustomException extends RuntimeException{
public CustomException(String message) {
super(message);
}
}
// 全局异常处理器
@Slf4j
@ResponseBody // 返回JSON数据
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理CustomException自定义业务异常
*/
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException ex){
return R.error(ex.getMessage());
}
}
总结:
世界上最遥远的 距离,是我在 if 里你在 else 里,似乎一直相伴又永远分离;
世界上最痴心的 等待,是我当 case 你是 switch,或许永远都选不上自己;
世界上最真情的 相依,是你在 try 我在 catch。无论你发神马脾气,我都默默承受,静静处理。到那时,再来期待我们的 finally。
😜 相 见 就 是 【 猿 分 】 🐒
.
👀 感谢您阅读完此文章 👀
.
❌ 如果文章中有错误的地方请指正 ✔️
.
✏️ 此文章参考尚硅谷教程笔记、Java相关书籍和个人学习经验总结的Java后端学习笔记 ⭐️
.
❓ 希望能够对你有所帮助 🎯
.
🔗 欢迎 【关注】【评论】【点赞】🚩
.
💪 感谢支持,一起加油,共同进步 🏃