> 文档中心 > 【JavaSE】为什么需要异常处理机制?Java异常详解 ———18张图,近万字带你彻底搞懂异常

【JavaSE】为什么需要异常处理机制?Java异常详解 ———18张图,近万字带你彻底搞懂异常

💁 个人主页:Nezuko627的博客主页
❤️ 支持我:👍 点赞 🌷 收藏 🤘关注
🎏 格言:立志做一个有思想的程序员 🌟
📫 作者介绍:本人本科软件工程在读,博客主要涉及JavaSE、JavaEE、MySQL、SpringBoot、算法等知识。专栏内容长期更新,如有错误,欢迎评论区或者私信指正!感谢大家的支持~~~

本篇学习目标:

  • ⭐️ 理解为什么需要异常处理机制;
  • ⭐️ 了解什么是异常,及编译时异常与运行时异常的区别;
  • ⭐️ 掌握常见的几种运行时异常的处理;
  • ⭐️ 熟练使用 try-catch-finally 以及 throws 的方式处理异常;
  • ⭐️ 知道 throws 与 throw 的区别;
  • ⭐️ 了解自定义异常,并懂得基本的使用;

本文来自专栏:JavaSE系列专题知识及项目 欢迎点击支持订阅专栏 ❤️
在这里插入图片描述

文章目录

  • 1 异常引入
  • 2 异常简介
    • 2.1 异常的概念
    • 2.2 常见异常体系图
  • 3 常见运行时异常举例
    • 3.1 NullPointerException
    • 3.2 ArrayIndexOutOfBoundsException
    • 3.3 ClassCastException
    • 3.4 NumberFormatException
  • 4 异常处理
    • 4.1 try-catch-finally 异常处理
    • 4.2 try - catch练习题(坑)
      • 4.2.1 阅读程序
      • 4.2.2 输入校验
    • 4.3 throws 异常处理
    • 4.4 自定义异常
      • 4.4.1 自定义异常实例
    • 4.5 throw 和 throws 的区别
  • 5 编程练习
  • 写在最后

1 异常引入

🌔 不知道初学Java 时,大家是不是和博主一样一脸懵:“这异常到底是个什么东东,有什么用嘞?” 今天,咱们就专门来展开讲讲异常。
还是那个教科书里面的标准例子,来看一下吧:
在这里插入图片描述
在例子中,我们将 0 作为除数进行运算,运行结果如下:
在这里插入图片描述
😢 程序控制台好像出现了不得了的东西!细细一看,原来是告诉我们出现了算术异常。不过只要再细心看一下代码,你就会发现:程序并没有执行完成,因为控制台并没有输出“程序运行结束标记”这句话!而是在计算 res 的时候,就中断了。 这就导致了一个很严重的问题:在我们实际开发中,一个完整的项目,文件可能都多达上千个,难道可以因为这样的小错误就直接崩溃,停止运行吗?
答案是否定的,因此, 我们需要使用异常处理机制,来提升项目的健壮性!
在这里插入图片描述
🍎Tips: 在idea编译器中,我们可以先选中代码块,然后使用快捷键 ctrl + alt + t 在弹出的二级菜单中,一键添加 try - catch ,(偷懒小技巧增加了~~~)
来看一下添加异常机制后,程序的运行情况吧!
🐜 代码如下:
在这里插入图片描述
🍓 运行结果:
在这里插入图片描述
🐘 虽然运行结果同样抛出了异常信息,但是,程序并没有因此而中止!而是继续向后执行,结束标记输出就是最好的证明~
怎么样?现在是不是就对异常有兴趣啦!来,进入正题,我们慢慢聊~


2 异常简介

2.1 异常的概念

在 Java 中,异常即为程序执行过程中发生的不正常情况 但是需要注意的是,程序员在编码过程中的逻辑与语法错误不属于异常的范畴!
🍓 程序执行过程中所发生的异常可以分为如下两大类:
1️⃣ Error: Java 虚拟机无法解决的严重问题。如: JVM系统内部错误、资源耗尽等。举例:栈溢出(StackOverflowError)
2️⃣ Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。分为两大类:

  1. 运行时异常: 又叫非受检异常,即程序运行时,发生的异常;
  2. 编译时异常: 又叫受检异常,即编程时,编译器检查出的异常。

图示如下:
在这里插入图片描述
🖊 助记:
编译时异常: 编译器检查出来的异常,必须处理,不然运行不了;
运行时异常: 编译器没有检查出来,程序可以跑,可以 选择性处理。

2.2 常见异常体系图

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。Java异常体系结构呈树状,常见异常的层次结构图如图所示:
在这里插入图片描述
📖 Throwable 实现了 Serializable 接口。向下分为 Error Exception。而 Exception 我们可以通过异常处理机制来解决。我们着重处理 RuntimeException运行时异常,其常见的子类如下,上面的图可能看不清,我们来放大看:
在这里插入图片描述


3 常见运行时异常举例

3.1 NullPointerException

空指针异常,当应用程序在需要对象的地方使用null时,抛出该异常。
🐜 示例代码:

public class NullPointerException {    public static void main(String[] args) { String s = null; System.out.println(s.length());    }}

🍓 结果:

Exception in thread “main” java.lang.NullPointerException: Cannot invoke “String.length()” because “s” is null
at exception.NullPointerException.main(NullPointerException.java:10)

3.2 ArrayIndexOutOfBoundsException

数组下标越界异常。 用非法索引访问数组时抛出该异常,即数组越界。
🐜 示例代码:

public class ArrayIndexOutOfBoundsException {    public static void main(String[] args) { int[] arr = {1, 2, 3}; System.out.println(arr[3]);  // 越界    }}

🍓 结果:

Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at exception.ArrayIndexOutOfBoundsException.main(ArrayIndexOutOfBoundsException.java:10)

3.3 ClassCastException

类型转换异常。当试图将一个对象强制转换为不是实例的子类时,抛出该异常。
🐜 示例代码:

public class ClassCastException {    public static void main(String[] args) { Animal dog = new Dog(); Dog d = (Dog)dog;  // 向下转型 Cat c = (Cat)dog;  // 该句错误!!!!    }}class Animal{}class Dog extends Animal{}class Cat extends Animal{}

🍓 结果:

Exception in thread “main” java.lang.ClassCastException: class exception.Dog cannot be cast to class exception.Cat (exception.Dog and exception.Cat are in unnamed module of loader ‘app’)
at exception.ClassCastException.main(ClassCastException.java:11)

3.4 NumberFormatException

数字格式异常。当应用程序试图将字符串转成一种数值类型,但字符串不能转换为适当格式时,抛出该异常。 使用异常我们可以确保输入满足条件的数字。
🐜 示例代码:

public class NumberFormatException {    public static void main(String[] args) { int num = Integer.parseInt("123.456");  // 转不了    }}

🍓 结果:

Exception in thread “main” java.lang.NumberFormatException: For input string: “123.456”
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at exception.NumberFormatException.main(NumberFormatException.java:9)


4 异常处理

异常处理即当异常发生时,对异常处理的方式。 主要有两种处理方式:

  1. try-catch-finally:程序员在代码中自行处理,捕获异常;
  2. throws:将异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM。示意图如下:
    main方法如果没有进行 try catch,默认会进行 throws。
    在这里插入图片描述

4.1 try-catch-finally 异常处理

Java 提供 trycatch 块来处理异常。try 块用于包含可能出错的代码,catch 块用于处理 try 块发生的异常。finally 块可选择性添加,用于执行始终需要执行的代码。

🅰️ 基本语法:

try{// 可能发生异常的代码// 将异常生成对应的异常对象,传递给 catch 块}catch(异常){// 对异常的处理}finally{// 不管 try 是否有异常,始终都要执行 finally 块的代码// 通常将需要释放资源的代码放在 finally}

🍓 使用细节:
1️⃣ 如果异常发生了,则异常后面的代码不会执行,直接进入到 catch 块。
在这里插入图片描述
2️⃣ 如果异常没有发生,则顺序执行 try 代码块,不会进入 catch 块。
在这里插入图片描述
3️⃣ 如果 try 代码块有多个异常,可以使用多个 catch 分别捕获并进行相应的处理。 但是要求 子类必须在父类前面! 值得注意的是,异常捕获的时候,当捕获到第一个,后面的将不再捕获。
在这里插入图片描述
4️⃣ 允许使用 try - finally ,但是这种做法相当于没有捕获异常,finally
相当于进行了善后处理, 即 程序还是会因为异常中断,但是会执行该代码块中的代码后再中断(垂死挣扎)

在这里插入图片描述

4.2 try - catch练习题(坑)

4.2.1 阅读程序

🐜请阅读下面代码,猜猜输出结果:

public class Exception01 {    public static int method(){ int i = 1; try {     i++;     String[] name = new String[3];     if(name[1].equals("ABC")){  // 发生了空指针异常  System.out.println("ABC");     } }catch (NullPointerException e){     return ++i; }finally {     ++i;     System.out.println("i = " + i); } return 0;    }    public static void main(String[] args) { System.out.println(method());    }}

🍎 结果:

i = 4
3

🍉 解析:在 if 语句中发生了空指针异常,try 块其余代码不执行。执行 catch 块代码,此时应该 return 3。但是由于 finally 块一定要被执行,因此,程序会先将 return 的 i 值暂时存储起来,去执行 finally 块的代码。所以先输出 i = 4 后返回3.

4.2.2 输入校验

🐜 题目要求:

请你编写一段程序,用于判断用户的输入:如果输入不是整数,就提示错误信息,直到输入正确为止。

🐟 思路分析:

  1. 创建 Scanner 对象;
  2. 使用循环去接收一个输入;
  3. 将该输入尝试转换成 int;
  4. 如果转换时发生异常,说明输入有误,不能转换;
  5. 如果没有抛出异常,则输入正确,提示即可。

🍓 参考代码:

public class TryCatch {    public static void method() { Scanner scanner = new Scanner(System.in); int num = 0; while (true) {     System.out.println("请输入一个整数: ");     try {  num = Integer.parseInt(scanner.next());  // 有可能抛出异常  break;  // 没有抛出则退出循环     } catch (NumberFormatException e) {  System.out.println("你输入的不是整数, 请重新输入!");     } } System.out.println("输入正确!");    } public static void main(String[] args) {     method(); }}

🍎 实验结果:
在这里插入图片描述

4.3 throws 异常处理

🆔 基本介绍
如果一个方法可能生成某种异常,但是 并不确定如何处理这些异常,则该方法应显式地声明抛出异常 ,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。在方法声明中抛出异常的列表,throws 后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。

🅰️ 基本语法:

方法名 throws 异常类1, 异常类2......{// 方法体}

🍓 使用细节:
1️⃣ 对于运行时异常,程序如果没有处理,默认就是 throws 的方式处理;
2️⃣ 子类重写父类的方法时,对抛出异常有一条规定:子类重写的方法,所抛出的异常类型要么与父类抛出的异常一致,要么为父类抛出的异常类型的子类型; 演示如下:
在这里插入图片描述
在这里插入图片描述

4.4 自定义异常

当程序出现了某些错误,但该错误信息并没有在 Throwable 子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
🐱 自定义异常的步骤:

🐈 1.定义类:自定义异常类名,继承 Exception 或者 RuntimeException
🐈 2. 如果继承了 Exception,属于编译异常;
🐈 3.如果继承了 RuntimeException,属于运行异常。

4.4.1 自定义异常实例

🐜来看一个需求:

当接收 Person 对象年龄时,要求范围在 18~120 之间,否则抛出自定义异常,并给出提示信息。(要求继承 RuntimeException)

🅰️ 参考代码:

public class Main {    public static void main(String[] args) { Person person = new Person(125);  // 设置年龄125 出现了异常    }}class Person{    private int age;    public Person(int age){ this.age = age; ageException();    }    // 判断异常    public void ageException(){ if(!(age >= 18 && age <= 120)){     throw new AgeException("年龄需要在18 ~ 120之间"); } System.out.println("范围正常");    }}// 自定义异常class AgeException extends RuntimeException{    public AgeException(String message){ super(message);    }}

🍎 结果:
在这里插入图片描述

4.5 throw 和 throws 的区别

🐜 区别一览表:

关键字 意义 位置 作用(关键字后面的跟屁虫)
throws 异常处理的一种方式 方法声明处 异常类型
throw 手动生成异常对象的关键字 方法体中 异常对象

5 编程练习

🍉 题目描述(题目摘自 bilibili 韩顺平 Java 课程 P456):

编写程序接收两个参数(整数),计算两数相除。要求使用方法 cal(int num1, int num2)。对于数据格式不正确(NumberformatException)、缺少命令行参数(ArrayIndexOutOfBoundsException)、除0进行异常处理(ArithmeticException)。

🐜 参考代码:

public class Main {    public static void main(String[] args) { // 先检验输入参数的个数 try {     if(args.length != 2){  throw new ArrayIndexOutOfBoundsException("参数个数不对");     }     // 把接收到的参数转成整数     int n1 = Integer.parseInt(args[0]);     int n2 = Integer.parseInt(args[1]);     double res = cal(n1, n2);  // 可能算数异常 } catch (ArrayIndexOutOfBoundsException e) {     System.out.println(e.getMessage()); } catch (NumberFormatException e){     System.out.println("参数格式不正确"); } catch (ArithmeticException e) {     System.out.println("算术异常,0不能做除数"); }    }    // 编写方法,计算    public static double cal(int n1, int n2){ return n1/n2;    }}

🐟 输入(配置如下图,注意用空格分隔):
在这里插入图片描述

🍎 结果:

算术异常,0不能做除数


写在最后

🌟以上便是本文的全部内容啦,后续内容将会持续免费更新,如果文章对你有所帮助,麻烦动动小手点个赞 + 关注,非常感谢 ❤️ ❤️ ❤️ !
如果有问题,欢迎私信或者评论区!
在这里插入图片描述

共勉:“你间歇性的努力和蒙混过日子,都是对之前努力的清零。”
在这里插入图片描述