Exception异常机制详细讲解

一、异常

1.1 什么是异常

  • 异常(exception),就是程序中出现的错误
  • 就好比你在工作的时候,突然家里出了点情况,中断了你工作,这就是出现了异常情况。

1.2 异常机制的作用

  • 通过打印出的异常信息,我们可以知道是哪里的代码出现了问题,并大概了解为什么会出现这个问题,方便我们去解决问题

1.3 常见的异常

  • 算术异常 ArithmeticException

  • 数组下标越界异常 ArrayIndexOutOfBoundsException

  • 空指针异常 NullPointerException

  • 类转换异常ClassCastException

  • 解析异常 ParseException

  • 堆栈内存溢出错误 StackOverflowError

2.3 异常的分类

  • 异常也是一种类,Throwable 类是 Java 语言中所有错误或异常的超类。

1. Error

  • Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。
  • 也就是Error一般都是严重问题,遇到必须里面立马解决,所以不应该捕获…
  • 例如:堆栈内存溢出错误 StackOverflowError

2. Exception

可以抛出,也可以捕获的异常

Exception子类:RuntimeException(运行时异常)和其他异常类

① 运行时异常

  • 这些异常在编译时不强制要求处理,通常是由程序中的错误引起的,例如 NullPointerException、ArrayIndexOutOfBoundsException 等,这类异常可以选择处理,但并非强制要求。

在这里插入图片描述

  • 这些类是: RuntimeException及其子类的都是运行时异常

在这里插入图片描述

② 编译期异常

  • 编译期异常是用户错误或问题引起的异常,这些异常在编译时强制要求程序员处理。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。

在这里插入图片描述

总结:

Throwable
Error
Exception
验证问题,不能捕获,只能抛出
运行时异常
编译期异常
是RuntimeException的子类
默认不用处理
除了RuntimeException的子类的都是
必须强制处理

二、异常的处理

我们知道异常的基本概念了,那异常如何处理呢?

  • 异常的处理只有两种方式

    • 抛出异常
    • 捕获异常

2.1 抛出异常

  • 什么是抛出异常?

    目前为止任何异常,默认的处理方式都是抛出

    所谓抛出异常就是直接将错误信息打印到控制台
    在这里插入图片描述

3.1 抛出异常语法

  • 前面讲到运行时异常,可以不用处理,通过上图也发现系统会默认自动抛出
  • 如果是编译期异常,想要抛出异常,语法是
    • 位置: 在方法参数列表后,{}前
    • 写:throws 异常类名,类名2,…
    public static void main(String[] args) 
        throws ArithmeticException,ArrayIndexOutOfBoundsException {
        
    }
  • 声明抛出异常后,什么效果?
  • 如果代码一切正常,虽然声明的有抛出异常,也不会在控制台打印异常信息
  • 如果代码真的有异常,声明了抛出异常,
    • 1错误信息就会在控制台打印
    • 2抛出异常后,后续代码不再执行
    // 以下代码中19行报错,4,5,6,7.7都不再执行
    public static void main(String[] args) {
        System.out.println(0.0 );
        m1();
        System.out.println(7.7 );
    }


    public static void m1() {
        System.out.println(1);
        System.out.println(2);
        m2();
        System.out.println(5);
        System.out.println(6);
    }

    public static void m2(){
        System.out.println(3);
        System.out.println(4 / 0);
        System.out.println(4 );
    }
  • 但是如果方法抛出的是编译期异常,谁调用这个抛出编译期异常的方法,那么哪个方法就得处理!!

在这里插入图片描述

  • 特殊的 ,关于抛出异常在重写方法时也有要求…
  • 子类的重写后,方法抛出的异常范围要 <= 父类的异常范围
  • 特殊的,如果父类方法没有抛出异常,那么子类方法内有异常也不能抛出,只能捕获

总结抛出异常

  • 哪里抛出的?
    • 方法签名上只是声明可能抛出的异常类型
    • 方法体内,执行到某一行代码,如果有错才会抛出
  • 抛给谁?
    • 如果有异常抛出,谁调用抛给哪个方法
    • 最终抛出到main
    • main方法抛出到jvm,jvm打印到控制台
  • 抛到哪?
    • 抛出到控制台
  • 抛出了啥?
    • 异常的线程信息
    • 异常类型
    • 异常原因
    • 异常位置

3.2 试图捕获异常

试图捕获(try-catch)

  • 语法
try{
    // 可能会有报错的代码
} catch (异常类名 对象名){
    // 如果抓到异常,执行这里
}

执行流程:

  • 代码正常运行,执行try后
  • 进入try执行,如果try内一切正常,catch就跳过不执行
  • 如果try内有异常
    • try内异常处后续不执行
    • catch捕获到异常后,就会执行
  • 无论try内有无异常,try-catch后的代码都能运行
    public static void main(String[] args) {

        System.out.println(1);
        System.out.println(2);

        try {
            System.out.println(3);
            System.out.println(4.1);
            System.out.println(4/0);
            System.out.println(4.2);
        }catch (ArithmeticException ae){
            System.out.println("捕获到了异常:"+ae );
        }

        System.out.println(5);

    }
  • 特殊情况1: 出现的异常和捕获的异常不一致,try-catch失效

在这里插入图片描述

  • 特殊情况2: 允许同时声明catch多个异常

在这里插入图片描述

  • 特殊情况3: 如果真需要catch写多个异常,用于去捕获多种异常的话,建议这么写,写一个Exception,直接捕获最大类异常,这样所有异常子类都可以捕获

image-20240603114043937

3.3 捕获异常与抛出异常的区别

1. 抛出异常

在这里插入图片描述

通过上图发现程序中断,后续代码无法执行

2.捕获异常

在这里插入图片描述

通过上图发现,当try代码块中出现异常后,catch代码块捕获到异常,执行catch中的语句,而且try-catch外面的语句正常执行

三、finally

  • finally配合try-catch使用
  • 作用: 最终一定会执行,即放在finally里面的代码,之前无论有无报错,无论是抛出还是捕获,fianlly里面的代码最终一定能执行

语法:

try{
    // ...
}catch(Exception e){
    
}finally{
    
}

或者

try{
    // ...   
}finally{
    
}

finally一般用在 关闭流/通道的场景中,用于及时释放资源

例如: IO流,jdbc连接

四、throw 异常的产生(创建)

  • 之前说的是抛出异常,捕获异常都是异常出现了之后的解决方案.

如何制造产生异常呢?

产生异常,两个步骤:

  • 创建异常对象
  • 通过throw 抛出异常对象
    • 需要注意,throw抛出的是编译期异常,需要强制处理
    • throw抛出的是运行时异常,可以默认不用处理

public class Demo5 {

    public static void main(String[] args) throws ParseException {
        String s = parseBirthday2("41011120240101123");
        System.out.println(s );
    }

    /**
      需求: 解析身份证号中的生日,要求身份证号长度18位,
      否则抛出异常
     */
    public static String parseBirthday(String idNumber) throws ParseException{
        if (idNumber.length() == 18) {
            return idNumber.substring(6,14);
        }
        // 抛出异常(编译期异常,需要处理)
        throw new ParseException("生日解析出错,格式不正确",1);
    }


    public static String parseBirthday2(String idNumber) {
        if (idNumber.length() == 18) {
            return idNumber.substring(6,14);
        }
        // 抛出异常(运行时异常,不用管)
        throw new RuntimeException("2222生日解析出错,格式不正确");
    }
}
  • 总结throw和throws…
throwthrows
位置方法体内方法签名上
后面写什么跟1个异常对象跟异常类名,且允许多个
作用一定会抛出异常的声明抛出的异常类型,但是不一定有异常

四、异常类的API

查阅API,发现所有异常,方法基本上都直接继承自Throwable类,常用的方法

  • 构造方法 Throwable(String message)
    • 所有的异常对象,都通过有参构造将异常信息传递给Throwable父类
    • 且这个message就是异常信息
  • String getMessage()
  • void printStackTrace()
  • String toString()
public class Demo6 {

    public static void main(String[] args) {
        try {
            System.out.println(1/0 );
        }catch (ArithmeticException ae) {
            // String message = ae.getMessage( );
            // System.out.println("message = " + message);
            //
            // String string = ae.toString( );
            // System.out.println("string = " + string);

            // 获得这些异常信息,将来将其输出到本地磁盘日志文件
            ae.printStackTrace();
        }
    }
}

五、自定义异常

自定义异常实现步骤

  1. 创建一个异常类,命名规范XxxxException
  2. 继承一个合适的父类
    1. 继承编译期异常
    2. 继承运行时异常
  3. 设计一个有参构造,将异常信息参数通过super传递给父类异常

如何使用自定义异常类:

  • 在需要使用的方法内部,通过throw+该异常对象,将其抛出

// 异常类

public class AgeOutOfBoundsException extends Exception{

    public AgeOutOfBoundsException(String msg){
        super(msg);
    }

}

// 使用异常

public class Dog {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) throws Exception{
        if (age <= 0 || age >= 100) {
            throw  new AgeOutOfBoundsException("年龄"+age+"越界!");
        }
        this.age = age;
    }
}

最后

如果感觉有收获的话,点个赞 👍🏻 吧。
❤️❤️❤️本人菜鸟修行期,如有错误,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍在这里插入图片描述

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值