Java — 异常

一、异常简介

就是程序出现了不正常的情况。

异常结构:

  • Throwable: 所有错误和异常的超类。
    • Error: 严重问题,不需要处理。
    • Exception: 异常类,表示程序本身可以处理的问题。
      • Checked Exception: 编译期不检查,出现问题后,需要回来修改代码。
      • Unchecked Exception: 编译期必须处理,否则程序不能通过编译、不能运行。

二、异常体系

2.1、Throwable 类

Throwable 类位于 java.lang 包下,它是 Java 语言中所有错误(Error)和异常(Exception)的父类。
Throwable 类包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace() 等接口用于获取堆栈跟踪数据等信息。

成员方法:

方法名说明
public Throwable fillInStackTrace()填写执行堆栈跟踪
public StackTraceElement[] getStackTrace()提供对 printStackTrace() 打印的堆栈跟踪信息的编程访问
public Throwable getCause()如果原因不存在或未知,则返回此 throwable 的原因或 null
public String toString()返回此可抛出的简短描述
public String getMessage()返回此 throwable 的详细消息字符串
public void printStackTrace()把 throwable 对象封装的异常错误信息输出在控制台

2.2、Error 类

Error 是 Throwable 的一个直接子类,它指示合理的应用程序不应该尝试捕获的严重问题。
这些错误在应用程序的控制和处理能力之外,编译器不会检查 Error。
对于设计合理的应用程序来说,即使发生了错误,本质上也无法通过异常处理来解决其所引起的异常状况。

常见 Error :

  • OutOfMemoryError:内存溢出错误;
  • UnsupportedClassVersionError:Java 类版本错误;

2.3、Exception 类

Exception 是 Throwable 的一个直接子类,它指示合理的应用程序可能希望捕获的条件。
Exception 又包括 Checked Exception(检查异常)和 Unchecked Exception(非检查异常)两大类别。

2.3.1、Checked Exception

Checked Exception 是编译器要求必须处理的异常,除了 RuntimeException 以及它的子类,都是 Checked Exception 异常。
我们程序编写时就必须处理此类异常,否则程序无法编译通过。

常见检查异常:

  • IOException:IO 异常;
  • SQLException:SQL 异常;

2.3.2、Unchecked Exception

Unchecked Exception 是编译器不要求强制处理的异常,包含 RuntimeException 以及它的相关子类。
我们编写代码时即使不去处理此类异常,程序还是会编译通过。

常见非检查异常:

  • NullPointerException:空指针异常;
  • ArrayIndexOutOfBoundsException:数组下标越界异常;

三、JVM 默认处理方案

若程序出现问题,我们没有做任何处理,最终 JVM 会做默认的处理。

  1. 把异常的名称,异常原因及异常出现的位置等信息输出在控制台。

  2. 程序停止执行。

示例:数组下标越界。

// 当数组下标越界,程序在编译阶段不会发生错误,但在运行时会抛出异常
public class Test_01 {
    public static void main(String[] args) {
        System.out.println("程序开始");
        int[] arr = {1, 2, 3};
        System.out.println("arr = " + arr[3]); // 程序在这里发生异常,提前结束运行
        System.out.println("程序结束"); // 这行代码没有执行
    }
}

运行:

程序开始
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at exception.ExceptionDemo01.main(ExceptionDemo01.java:17)

异常原因:由于访问了数组中不存在的元素,所以代码停止执行并打印了相关的异常信息,此信息为堆栈跟踪。

异常信息:

  • Exception in thread “main”(异常位于主线程 main 中)
  • java.lang.ArrayIndexOutOfBoundsException(异常类型)
  • 3(异常详细信息)
  • at exception.ExceptionDemo01.main(Test_01.java:17)(异常发生位置)

四、异常处理

若程序出现问题,我们需要自己来处理,在 Java 语言中,异常处理机制分为两部分。

  • 抛出异常(throws)
    • 当一个方法发生错误时,会创建一个异常对象,并交给运行时系统处理。
    • 当前方法不处理,而是声明抛出,由该方法的调用者来处理。
  • 捕获异常(try … catch …)
    • 在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器。
    • 在当前方法中使用 try-catch 的语句块来处理异常。

Java 通过 5 个关键字来实现异常处理,分别是:throwthrowstrycatchfinally,异常总是先抛出后捕获的。

五、捕获异常

格式:

try {
    // 可能产生异常的代码
} catch (异常类名 变量名) {
    // 捕获并处理try抛出的异常类型,记录日志|打印异常信息|继续抛出异常
} catch (异常类名N 变量名) {
    // 捕获并处理try抛出的异常类型,记录日志|打印异常信息|继续抛出异常
} finally {
    // 无论是否发生异常,都将执行的代码块
}

流程:

​ ① 程序从 try 里面的代码开始执行。

​ ② 出现异常,会自动生成一个异常类对象,该异常对象将被提交给 Java 运行时系统。

​ ③ 当 Java 运行时系统接收到异常对象时,会到 catch 中去找匹配的异常类,找到后进行异常的处理。

​ ④ 处理异常执行完毕之后,程序还可以继续往下执行。

​ ⑤ 无论程序是否发生异常,finally 中代码块都会执行。

示例:

public class Test_02 {
    public static void main(String[] args) {
        System.out.println("程序开始");
        int[] arr = {1, 2, 3};
        try {
            System.out.println("arr = " + arr[3]); // 可能发生异常的代码
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace(); // 处理异常(打印异常信息)
        } finally {
            System.out.println("无论是否发生异常,都将执行的代码块");
        }
        System.out.println("程序结束");
    }
}

运行:

程序开始
无论是否发生异常,都将执行的代码块
程序结束
java.lang.ArrayIndexOutOfBoundsException: 3
	at step_05_exception.Test_02.main(Test_02.java:8)

将第 6 行代码 arr[3] 改为 arr[2] 再运行:

程序开始
arr = 3
无论是否发生异常,都将执行的代码块
程序结束

六、抛出异常

6.1、throw

用在方法体内,跟的是异常对象名,表示抛出异常,由方法体内的语句处理。
执行 throw 一定抛出了某种异常。

示例:

public class Test_03 {
    public static void main(String[] args) {
        System.out.println("程序开始");
        divide(2, 0); // 调用除法
        System.out.println("程序结束");
    }

    // 除法方法
    public static void divide(int a, int b) {
        System.out.println("除法开始");
        if (b == 0) {
            throw new ArithmeticException("除数不能为零"); // 抛出异常、但没有处理异常、异常发生时程序中断不再往下执行
        }
        System.out.println(a / b);
        System.out.println("除法结束");
    }
}

运行:

程序开始
除法开始
Exception in thread "main" java.lang.ArithmeticException: 除数不能为零
	at step_05_exception.Test_03.divide(Test_03.java:15)
	at step_05_exception.Test_03.main(Test_03.java:7)

6.2、throws

用在方法声明后面,跟的是异常类名,表示抛出异常,由该方法的调用者来处理。
表示出现异常的一种可能性,并不一定会发生这些异常。

格式:

修饰符 返回值类型 方法名 (参数列表) throws 异常类名1, 异常类名2, 异常类名3... {   
    //方法体
}

示例:

public class Test_04 {
    public static void main(String[] args) {
        System.out.println("程序开始");
        try {
            divide(2, 0); // 调用除法
        } catch (ArithmeticException e) {
            e.printStackTrace(); // 处理异常(打印异常信息)
        }
        System.out.println("程序结束");
    }

    // 抛出异常,不在方法中处理,谁调用该方法谁处理
    public static void divide(int a, int b) throws ArithmeticException {
        System.out.println("除法开始");
        System.out.println(a / b);
        System.out.println("除法结束");
    }
}

运行:

程序开始
除法开始
程序结束
java.lang.ArithmeticException: / by zero
	at step_05_exception.Test_04.divide(Test_04.java:19)
	at step_05_exception.Test_04.main(Test_04.java:8)

七、自定义异常

示例:

public class Test_05 {
    public static void main(String[] args) {
        System.out.println("程序开始");
        checkAge(200); // 输入0~120范围之外的年龄
        System.out.println("程序结束");
    }

    // 检查年龄方法
    static void checkAge(int age) {
        System.out.println("开始检查");
        if (age < 0 || age > 120) {
            throw new ageException("年龄应在0~120之间");
        } else {
            System.out.println("年龄合法:" + age + "岁");
        }
        System.out.println("结束检查");
    }

    // 自定义年龄异常,继承运行时异常
    static class ageException extends RuntimeException {
        public ageException() {
        }

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

运行:

程序开始
开始检查
Exception in thread "main" step_05_exception.Test_05$ageException: 年龄应在0~120之间
	at step_05_exception.Test_05.checkAge(Test_05.java:14)
	at step_05_exception.Test_05.main(Test_05.java:6)

第 6 行代码 checkAge() 方法中输入0~120范围之内的年龄再运行:

程序开始
开始检查
年龄合法:18岁
结束检查
程序结束
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值