什么是异常?如何处理和定义异常呢?

一、异常

1.1 什么是异常

异常(exception),就是程序中出现的错误

1.2 之前见过的异常

算术异常 ArithmeticException

数组下标越界异常 ArrayIndexOutOfBoundsException

空指针异常 NullPointerException

类转换异常 ClassCastException

解析异常 ParseException

堆栈内存溢出错误 StackOverflowError

1.3 异常的分类

在java中,所有的错误(error)或者异常(exception)都是默认可以被抛出到控制台被看见的,这样才能方便解决

所以,可抛出就是所有异常/错误的共性,所以java就设计了一个父类: Throwable;

java的异常(Exception)和错误(Error)就是Throwable的子类


Error: 只能抛出,不能捕获的异常就是错误!!

  • ps: Error一般都是严重问题,遇到必须里面立马解决,所以不应该捕获....

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


Exception异常又可再细分

  • 运行时异常

    • 凡是RuntimeException及其子类的都是运行时异常

    • 运行时异常,默认无需处理

  • 编译期异常

    • 除了Runtime以前子类都是编译期

    • 编译期,默认是要强制处理(怎么处理都行,但是要处理)

二、异常的处理

异常的处理只有两种方式

  • 抛出异常

  • 捕获异常

2.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 );
    }

运行时异常,可以主动抛出,也可以不用抛出

但是如果方法抛出的是编译期异常,谁调用这个抛出编译期异常的方法,那么哪个方法就得处理!!

image-20240603105655398

特殊的 ,关于抛出异常在重写方法时也有要求.....

子类的重写后,方法抛出的异常范围要 <= 父类的异常范围

特殊的,如果父类方法没有抛出异常,那么子类方法内有异常也不能抛出,只能捕获

总结抛出异常

  • 哪里抛出的?

    • 方法签名上只是声明可能抛出的异常类型

    • 方法体内,执行到某一行代码,如果有错才会抛出

  • 抛给谁?

    • 如果有异常抛出,谁调用抛给哪个方法

    • 最终抛出到main

    • main方法抛出到jvm,jvm打印到控制台

  • 抛到哪?

    • 抛出到控制台

  • 抛出了什么?

    • 异常的线程信息

    • 异常类型

    • 异常原因

    • 异常位置

image-20240603112025039

2.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失效

image-20240603113457000

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

image-20240603113817871

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

image-20240603114043937

捕获异常与抛出异常最大的区别就是,抛出异常后,代码还能继续执行...

如下,代码能运行 1234789...

public class Demo3 {
​
    public static void main(String[] args) {
        System.out.println(1);
        m1( );
        System.out.println(9 );//运行结果:1 2 3 4 (异常信息) 7 8 9
    }
​
    public static void m1() {
        System.out.println(2);
        m2( );
        System.out.println(8 );
    }
​
    public static void m2() {
        System.out.println(3);
        try {
            System.out.println(4);
            System.out.println(5 / 0);
            System.out.println(6);
        } catch (Exception e) {
            System.out.println(e);
        }
        System.out.println(7 );
    }
}

2.3 finally

finally配合try-catch使用

单词释义: 最终的

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

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

或者

try{
    // ...   
}finally{
    
}

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

例如: IO流,jdbc连接

三、异常的产生(创建)

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

现在,要学习如何产生异常...

产生异常,两个步骤:

  • 创建异常对象

  • 通过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
位置方法体内方法签名上
后面写什么跟一个异常对象跟异常类名,且允许多个
作用一定会抛出异常的声明抛出的异常类型,但是不一定有异常

四、异常的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) {
            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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值