1. 什么是程序的异常?

    在计算机编程中,程序的异常是指在执行过程中发生的错误或异常情况。当程序遇到异常时,它会中断正常的执行流程,并进行相应的异常处理。异常可以是预期的,例如用户输入错误或文件不存在等,也可以是未预期的,例如内存溢出或除以零等。

注意:异常并不是逻辑错误,比如要实现a+b,但是写成了a-b,这种就不算异常!

  1. Throwable

​ java.lang.Throwable类是Java程序执行过程中发生的异常事件对应类的根父类,着重关注它的子类,可通过API帮助文档查询。

​ 编译异常:在Throwable子类中除了运行时异常的。

​ 运行异常:

  1. 异常处理
    方式一 try - catch - finally

​ 程序在执行的过程中,一旦出现异常,就会在出现异常的代码处,生成对应的异常类对象,并抛出。

​ 基本结构:

 try {			//有作用域的概念
            Scanner sc = new Scanner(System.in);
            int num = sc.nextInt();
            System.out.println(num);
            sc.close();
        }catch (InputMismatchException e){		//异常类型如果有继承关系,那么子类必须写在父类的上面,否则会报错!!!
            System.out.println("输入的类型有误!");
        }finally{
     //不管有没有异常都会执行的逻辑,无论什么情况都会执行的代码,包括有return语句依旧会执行!!!如有catch和try有return语句,那么先执行finally语句,然后执行根据异常情况执行return语句,唯一情况:System.exit(0);使用一些资源之后需要关闭,故而需要这个结构
 }

捕获异常可以直接输出,如下所示:

    public static void test02(){
        try {
            Scanner sc = new Scanner(System.in);
            int num = sc.nextInt();
            System.out.println(num);
            sc.close();
        }catch (InputMismatchException e){
            //输出异常信息
            e.printStackTrace();
        }
    }

注意:如果是运行时异常,则不需要做异常处理,运行报错修改代码就行。如果是编译异常,就必须做异常处理。

方式二 - throw

1、异常信息向上抛,抛给调用的方法,所以调用抛出异常方法的方法需要处理异常。

2、子类重写的方法抛出的异常类型可以与父类被重写的方法抛出的异常类型相同,或者是父类异常类型的子类,不能写它的父类。如果父类方法没有抛出异常,那么子类重写方法时也不能抛出异常,接口也一样。

import java.util.NoSuchElementException;        //父类异常

public class Father {
    public void show1() throws NoSuchElementException{
        System.out.println("我是父类(1)!");
    }

    public void show2() throws NoSuchElementException{
        System.out.println("我是父类(1)!");
    }

}

import java.util.NoSuchElementException;        //父类异常
import java.util.InputMismatchException;        //子类异常

public class Son extends Father {
    @Override
    public void show1() throws NoSuchElementException {
        System.out.println("我是子类(1)");
    }

    @Override
    public void show2() throws InputMismatchException {
        System.out.println("我是子类(2)");
    }
}

public class MyTest {
    public static void main(String[] args) {
        Son son = new Son();
        son.show1();
        son.show2();
    }
}

输出结果:

我是子类(1) 我是子类(2)

4、如何选择两种异常处理结构?

①、涉及到资源一定要被执行,需要使用try -catch结构

②、父类方法没有抛出异常,那么子类重写时有异常时需要使用try catch

③、假如有一个方法里面调用了实现不同功能的方法,并且这几种方法有一种递进关系,那么会使用到try -catch结构,然后统一在main方法中处理异常结构。

5、手动抛出异常

1、在实际开发过程中,如果出现不满足具体场景代码的问题,我们就有必要手动抛出一个异常。例如:

public class Person {
    private int age;


    public Person() {
    }

    public Person(int age) {
        this.age = age;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) throws RuntimeException{
        if(age < 0 || age > 120){
            throw new RuntimeException("输入年龄非法!");
        }else {
            this.age = age;
        }
    }

    public String toString() {
        return "Person{age = " + age + "}";
    }
}

//测试类
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入年龄:");
        int num = scanner.nextInt();
        //调用Person类的set方法
        try {
            p.setAge(num);
        }catch (RuntimeException e){
            System.out.println(e.getMessage());
        }

    }

}

输出结果:

请输入年龄:444 输入年龄非法!

方法抛出编译异常时,需要在方法后面写上throws 异常类型!

6、自定义异常类

6.1、如何自定义异常类?

①、继承于现有的异常类,通常继承RuntimeException或者Exception

②、通常需要提供几个重载的构造器

③、提供一个全局静态变量,声明为static final long serialVersionUID = -7034897190745766939L(这个数字要根据实际情况进行修改!!)

6.2、如何使用也异常类的作用?

在手动抛出异常的时候会使用到。并且我们希望能够通过异常的名称找出异常出现的位置,所以我们需要使用到自定义异常类。

如下所示:

//Person类
package Test02;

public class Person {
    private int age;


    public Person() {
    }

    public Person(int age) {
        this.age = age;
    }

    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) throws PersonAgeSetError {
        if (age < 0 || age > 120) {
            throw new PersonAgeSetError("输入年龄非法!");
        } else {
            this.age = age;
        }
    }

    public String toString() {
        return "Person{age = " + age + "}";
    }
}

自定义异常类:

package Test02;

public class PersonAgeSetError extends RuntimeException {
    static final long serialVersionUID = -703489719766939L;

    public PersonAgeSetError() {
        super();
    }

    public PersonAgeSetError(String message) {
        super(message);
    }

    public PersonAgeSetError(String message, Throwable cause) {
        super(message, cause);
    }

    public PersonAgeSetError(Throwable cause) {
        super(cause);
    }

}

测试类:

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Person p = new Person();
        Scanner scanner = new Scanner(System.in);

        System.out.print("请输入年龄:");
        int num = scanner.nextInt();

        try {
            p.setAge(num);
            System.out.println("年龄设置成功");
        } catch (PersonAgeSetError e) {
            System.out.println("年龄设置失败: " + e.getMessage());
        }
    }
}

输出结果:

请输入年龄:4444 年龄设置失败: 输入年龄非法!