Loading

异常详解

🦔异常

发现错误的理想时机是在编译阶段,也就是在运行程序之前。然而编译期间并不能找到所有的错误,余下的问题必须在运行期间解决。这就需要错误源能够通过某种方式,把适当的信息传递给某个接受者——该接受者知道如何正确处理这个问题。

​ Java编程思想(第四版)

概念

异常指不期而至的各种状况,如除0操作、用户输入不合法、内存溢出、读取文件不存在等等情况。

Java异常是一个描述在代码段中发生异常的对象,当发生异常时,一个代表该异常的对象被创建并且在导致该异常的方法中被抛出,而该方法可以选择自己处理或者传递该异常。

使用异常不仅降低了处理错误代码的复杂度,并且使代码变得更加健壮。

异常的体系结构

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。

Java异常层次结构图:

在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception

  • Error

    Java虚拟机无法解决的严重问题,如:JVM内部错误,资源耗尽等情况。一般不编写针对性的代码进行处理。

  • Exception

    因为其他编程错误或偶然的外在因素导致的一般性问题,如:控制针访问、视图读取不存在的文件、网络连接中断、数组索引越界等情况。可以编写针对性的代码进行处理。

遇到这些异常情况有两种解决办法:一种时抛出异常,一种是捕获异常。

如果我们遇见异常,解决是最好的,不能解决交由上层环境,如果上层环境还是不能解决,继续向上抛,直到main()方法将异常抛给JVM,JVM将使用默认的异常处理程序:终止程序,打印异常信息

捕获异常的最佳时机是在编译期间,但有些异常是在运行期间才会发生的,如:除0操作、数组索引越界

所以,Exception又分为

  • 编译时异常(受检异常)

    是指编译器要求必须处理的异常,是程序在运行期间由于外界因素导致的一般性错误。如果不进行处理,可能导致意想不到的结果。一般编译器会进行提示。如:IOException、SQLException、ClassException

  • 运行时异常

    编译不要求强制处理的异常,一般是在编程过程中的逻辑错误,可以不做处理。因为这类异常非常普遍,如进行全局处理,会影响程序的可读性以及运行效率。程序员应该积极避免这类异常。对于这类异常,或者叫Bug进行try...catch处理是毫无意义的。java规定,运行时异常将由运行时系统自动抛出,允许应用程序忽略运行时异常

除了RuntimeException和Error其余都是受检异常,会在编译期间检测异常

常见异常

  • ArrayIndexOutOfBoundsException

    int[] array = {1,2,3,4,5};
    for (int i = 0; i < 6; i++) {
        System.out.println(array[i] + "");
    }
    
  • NUllPointException

    int[] array = {1,2,3};
    array = null;
    for (int i = 0; i < array.length; i++) {
        System.out.println(array[1]);
    }
    
  • ArithmeticException

    int x = 0;
    int y = 3 / x;
    System.out.println(y);
    
  • ClassCastException

    Object date = new Date();
    CommonException exception = new CommonException();
    exception = (CommonException) date;
    

异常处理机制

1)抛出异常

对于在当前环境中没办法获得更多信息去处理这个异常,或者在当前环境中处理异常没有意义的时候,我们需要把这个异常抛出这个环境,交由上层方法调用者去处理。

抛出异常后,会有几件事情发生:

  1. 使用new在堆上创建一个异常对象。
  2. 终止当前的执行路径,并且在当前环境中弹出对异常对象的引用,只要异常被捕获,根据这个异常对象的引用,就能控制程序的指向。
  3. 异常处理机制接管程序,并寻找一个恰当的地方(异常处理程序或异常处理器),继续执行程序,它的任务是将程序从错误状态中恢复,使程序要么换种方法运行,要么继续运行下去。

2)捕获异常

在方法抛出异常后,系统转而寻找合适的异常处理器。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当方法抛出的异常类型和异常处理器所能处理的异常类型相符,或是异常处理器处理异常类型的子类时,达到匹配。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直到找到含有合适异常处理器的方法执行,当运行时系统遍历调用栈而未找到合适的异常处理器的时候,则运行时系统终止,即Java程序终止

异常处理语法

1)try...catch

try代码块中的区域是监控区域,当try代码块中的代码出现异常的时候,自动抛出异常,创建异常对象

catch代码块用于捕获异常,执行异常程序,catch中的代码将保证程序正常运行下去

一个语句中产生多种异常时,这时需要多重catch语句,排列规则是:先小后大,先子类再父类,否则捕获底层异常的catch子句会被屏蔽

try语句可以被嵌套,如果内层try中产生异常,会先匹配内层catch语句,不匹配再和外层catch语句进行匹配

对于一些资源来说,并不属于Java资源你,不由JVM进行管理,所以我们在打开后需要自己手动关闭,可以使用try开启资源自动管理功能,执行完语句, 资源自动关闭,交由JVM进行管理

// 语法
try(打开资源){
    
}
public void indexExp() {
    /*
     * Description: 对IndexOutOfBoundsException捕获,执行PlanB
     * @author: 苏无及
     * @date: 2022/8/6 19:56
     * @param:[]
     * @return:void
     */
    int[] array = {1, 2, 3, 4, 5};
    try {
        for (int i = 0; i < 6; i++) {
            System.out.println(array[i] + "");
        }
    } catch (IndexOutOfBoundsException e) {
        System.out.println("IndexOutOfBoundsException");
    }
}

/*
	测试
*/
@Test
public void test1(){
    CatchException exception = new CatchException();
    exception.indexExp();
}

2)throw

用于抛出异常,手动创建异常对象,不需要JVM创建对象

程序执行完throw之后立即停止执行,throw之后的语句不会执行,最邻近的try块检测自己是否有与异常对象相匹配的catchh语句,如果发现匹配的块,控制转向该语句,没有发现则使次包围的try进行检查,如果一直没有发现,程序将执行结束

所有的java内置的运行时异常创建对象,有两个构造函数,一个空参,一个带有一个字符串参数,参数用于指定异常的描述,可以通过print直接打印对象,或者使用getMessage()方法从而得到字符串

public void throwIndexExp() {
    /*
     * Description: throw抛出异常
     * @author: 苏无及
     * @date: 2022/8/7 20:43
     * @param:[]
     * @return:void
     */
    int[] array = {1, 2, 3, 4, 5};
    for (int i = 0; i < 6; i++) {
        if (i == 5){
            throw new IndexOutOfBoundsException("数组索引越界!");
        }
        System.out.println(array[i] + "");
    }
}

/*
	测试
*/
@Test
public void test2(){
    CatchException exception = new CatchException();
    try {
        exception.throwIndexExp();
    } catch (IndexOutOfBoundsException e) {
        System.out.println("数组索引越界");
    }
}

3)throws

用于在方法签名中,声明该方法可能抛出的异常类型,告知方法调用者

public void throwsIndexExp() throws IndexOutOfBoundsException{
    /*
     * Description: 使用throws声明异常类型
     * @author: 苏无及
     * @date: 2022/8/7 20:53
     * @param:[]
     * @return:void
     */
    int[] array = {1, 2, 3, 4, 5};
    for (int i = 0; i < 6; i++) {
        System.out.println(array[i] + "");
    }
}

/*
	测试
*/
@Test
public void test3(){
    CatchException exception = new CatchException();
    try {
        exception.throwsIndexExp();
    } catch (IndexOutOfBoundsException e) {
        System.out.println("数组索引越界!");
    }
}

4)finally

finally语句块总会被执行,不管catch中的语句是否执行。主要用于回收在try里打开的资源。

public void finallyExp(){
    /*
     * Description: 使用finally
     * @author: 苏无及
     * @date: 2022/8/7 20:59
     * @param:[]
     * @return:void
     */
    int[] array = {1, 2, 3, 4, 5};
    try {
        for (int i = 0; i < 6; i++) {
            System.out.println(array[i] + "");
        }
    } catch (IndexOutOfBoundsException e) {
        System.out.println("数组索引越界!");
    } finally {
        System.out.println("finally");
    }
}

/*
	测试
*/
@Test
public void test4(){
    CatchException exception = new CatchException();
    exception.finallyExp();
}

执行顺序

对于try、catch、finally的执行顺序:

  • 如果try中没有异常,try-->finally
  • 如果try中有异常,try-->catch-->finally
  • 当try、catch中有return时,也会执行finally,注意return的时候注意是否受finally的影响
  • finally中有return的时候,会直接在finally中退出,导致try、catch中的return失效

throw和throws的区别

  • trow出现在函数体中,throws出现在方法签名中
  • throws表示可能出现的异常类型,throw则一定抛出某个异常对象
  • 两者都是抛出异常,交由上次环境进行处理,如果还是不处理,JVM默认处理
  • throws可以表示抛出多个异常类型,用逗号分隔

自定义异常

  • 创建异常类(见名知意)
  • 继承内置异常类
  • 提供有参无参构造
// 自定义年龄越界异常类
public class AgeOutOfBoundsException extends RuntimeException {
    
    public AgeOutOfBoundsException() {
    }

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

Throwable的成员方法

  • String getMessage()

    返回此throwable的详细消息字符串

    返回的是在创建异常对象时,当作参数传入的字符串

    throw new IndexOutOfBoundsException("数组索引越界!");
    ...
    java.lang.IndexOutOfBoundsException: 数组索引越界!
    
  • String toString()

    返回此可抛出的简短描述

    java.lang.ArrayIndexOutOfBoundsException: 5
    
  • void printStackTrace

    把异常的错误信息输出在控制台

    java.lang.ArrayIndexOutOfBoundsException: 5
    	at com.dong.exceptionDemo.CommonException.indexOutExp(CommonException.java:25)
    	at com.dong.exceptionDemo.CommonExceptionTest.test1(CommonExceptionTest.java:20)
    
posted @ 2022-08-07 21:19  苏无及  阅读(82)  评论(0编辑  收藏  举报