1.什么是异常

在程序运行的过程中,比如发生程序运行时磁盘空间不足,工作时电脑蓝屏,网络连接中断,被加载的类不存在等等。。针对这些不正常的情况,Java语言引入了异常,以异常类的形式对这些非正常的情况进行封装,并通过异常处理机制对程序运行时发生的问题进行处理。。

public class test {
    public static int divide(int x,int y){
        return x/y;
    }
    
    public static void main(String[] args) {
        int result=divide(4,0);
        System.out.println(result);
    }
}

alt

上述代码产生了ArithmeticException的异常,这个异常只是Java异常类中的一种,在Java中还提供了大量的异常类,这些类继承自java.lang.Throwable类。。

2.Throwable类

alt

从图中可以看出,Throwable类哎有两个直接子类Error和Exception,其中Error代表程序中的错误, Exception代表程序中产生的异常。

  • Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽时的错误,是比较严重的,仅靠修改程序本身是不能恢复的,如系统崩溃,虚拟机错误等。

  • Exception类称为异常类,它表示程序本身可以处理的错误。在Java程序开发中进行的异常处理,都是针对Exception类及其子类的,在Exception类的众多子类中有一个特殊的RunTimeException类,该类及其子类用于表示运行时的异常。除了此类,Exception类下所有其他的子类都用于表示编译时的异常。

Throwable类常用方法

方法申明 功能描述
String getMessage() 返回此throwable的详细消息字符串
void printStackTrace() 将此throwable及其追踪输出至标准错误流
void printStackTrace(PrintStream s) 将此throwable及其追踪输出到指定的输出流

3.异常的类型

3.1 编译时的异常

在Exception的子类中,除了RunTimeException类及其子类外,其他子类都是编译时的异常。

处理编译时的异常有两种方式:

(1)使用try...catch语句对异常进行捕获处理。

(2)使用throws关键字申明抛出异常,让调用者对其处理。

3.2 运行时的异常

RunTimeException类及其子类都是运行时的异常。运行时的异常是程序运行时由Java虚拟机自动进行捕获处理的,即使没有try...catch语句或使用throws关键字申明抛出,程序也能够编译通过,只是在运行过程中可能报错。。

常见的运行时异常

异常类名称 异常类说明
java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。
java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。
java.lang.IllegalArgumentException 方法传递参数错误。
java.lang.ClassCastException 数据类型转换异常。
java.lang.NoClassDefFoundException 未找到类定义错误。
SQLException SQL 异常,常见于操作数据库时的SQL 语句错误。
java.lang.InstantiationException 实例化异常。
java.lang.NoSuchMethodException 方法不存在异常。

注:运行时的异常一般是由于程序中的逻辑错误引起的,在程序运行时无法恢复。

4.异常处理

4.1 try...catch和finally

当程序发生异常时,会立即中止,无法继续向下执行。Java中提供了一种对异常进行处理的方式---异常捕获,目的是为了保证程序能够有效的进行。。

		try{
            //可能发生异常的语句
        }catch (Exception类及其子类 e){
            //对捕获的异常进行相应的处理
        }
public class test {
    public static int divide(int x,int y){
        try{
            return x/y;
        }catch (Exception e){
            System.out.println("捕获到的异常信息为:"+e.getMessage());
        }
        return -1;
    }

    public static void main(String[] args) {
            int result=divide(4,0);
            System.out.println(result);

            int result1=divide(-1,1);
            System.out.println(result1);
    }
}

alt

上述代码输出了两个-1,不好分辨那个-1是发生异常产生的,因此进行代码的修改,如下:

public class test {
    public static int divide(int x,int y){
        return x/y;

    }

    public static void main(String[] args) {
        try{
            int result=divide(4,0);
            System.out.println(result);
        }catch (Exception e){
            System.out.println("程序发生异常");
        }

    }
}

alt

finally关键字

try{
    //可能发生异常的语句
}catch (Exception类及其子类 e){
    //对捕获的异常进行相应的处理
}finally{
    //无论代码是否发生异常,都会执行
}
public class test {
    public static int divide(int x,int y){
        return x/y;

    }

    public static void main(String[] args) {
        try{
            int result=divide(4,0);
            System.out.println(result);
        }catch (Exception e){
            System.out.println("程序发生异常");
        }finally {
            System.out.println("执行finally,无论代码是否发生异常,都会执行");
        }

    }
}

alt

4.2 throws关键字

在代码开发的时候,开发者通常会意识到可能出现的异常,可以直接通过try...catch对异常进行处理,但有的时候,方法中的代码是否出现异常,开发者并不明确或者不急于处理,Java中允许这种异常从当前的方法中抛出,然后后续调用者在使用时在进行对异常进行处理。。

public class test {
    public static int divide(int x,int y) throws Exception{
        return x/y;

    }

    public static void main(String[] args) throws Exception {
        int result=divide(4,0);
        System.out.println(result);
    }
}

alt

在调用divide()方法时,由于该方法在方法申明的时候抛出了异常,所以在调用divide()方法的时候是必须要进行处理,否则编译就会报错。。。

public class test {
    public static int divide(int x,int y) throws Exception{
        return x/y;

    }

    public static void main(String[] args) {
        try{
            int result=divide(4,0);
            System.out.println(result);
        }catch (Exception e){
            System.out.println("程序发生异常");
        }finally {
            System.out.println("执行finally,无论代码是否发生异常,都会执行");
        }

    }
}

alt

上述代码对抛出的异常进行了异常捕获处理,所以程序可以编译通过,并正常执行。。。

4.3 throw关键字

除了可以通过throws关键字抛出异常外,还可以使用throw关键字抛出异常。与throws有所不同的是,throw用在方法体中,并且抛出的是一个异常类对象,而throws关键字用在方法申明中,用来指明方法可能抛出多个异常。。

public class test {
    public static void printAge(int age) throws Exception {
        if(age<0){
            throw new Exception("输入的年龄有误,请输入正确的年龄!!");
        }else {
            System.out.println("此人的年龄为:"+age);
        }
    }
    public static void main(String[] args) {
        int age=-2;
        try {
            printAge(age);
        }catch (Exception e){
            System.out.println("捕获的异常信息为:"+e.getMessage());
        }

    }
}

alt

注:通过throw关键字抛出异常后,还需要throws关键字或try...catch对异常进行处理

需要注意的是,如果throw抛出的是Error,RunTimeException或它们的子类异常对象,则无需使用throws或try...catch对异常进行处理。。

4.4 自定义异常

class DivideByMinusException extends Exception{
    public DivideByMinusException(){
        super();
    }
    public DivideByMinusException(String message){
        super(message);
    }

}

public class test {
    public static int divide(int x,int y) throws DivideByMinusException {
        int result=x/y;
        if(y==0){
            throw new DivideByMinusException("除数是0 !!!");
        }else {
            return result;
        }
    }
    public static void main(String[] args) {
        try {
            divide(4,0);
        }catch (Exception e){
            System.out.println("捕获的异常信息为:"+e.getMessage());
        }

    }
}

alt