【Java】13 异常

时间:2022-07-26
本文章向大家介绍【Java】13 异常,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在程序设计和运行的过程中,尽管 Java 提供了便于写出简洁、安全代码的方法,并且程序员也尽可能规避错误,但使程序被迫停正的错误仍然不可避免。为此,Java 提供了异常处理机制来帮助程序员检查可能出现的错误,提高了程序的可读性和可维护性。

一、异常

   异常指的是程序在执行过程中,出现的非正常的情况,最终会导致 JVM 的非正常停止。异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。在 Java 等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java 处理异常的方式是中断处理。

1.1 异常的分类

编译时期异常:checked 异常。在编译时期,就会检查,如果没有处理异常,则编译失败。 运行时期异常:runtime异常。在运行时期,检查异常,在编译时期,运行异常不会编译器检测(不报错)。

常见异常 ParseException:解析异常 NullPointerException:空指针异常 ClassCastException:类型转换异常 ArithmeticException:数学运算异常 NumberFormatException:数字格式化异常 ArrayIndexOutOfBoundsException :数组下标越界异常

1.2 常用方法

方法名

说明

void printStackTrace( )

将该异常的跟踪栈信息输出到标准错误输出

void printStackTrace( )

将该异常的跟踪栈信息输出到指定输出流

String getMessage( )

返回该异常的详细描述字符串

StackTraceElement[ ] getStackTrace( )

返回异常的跟踪栈信息

1.3 异常产生的过程


二、异常处理机制

2.1 使用 try ··· catch 捕获异常

   如果执行 try 块里的业务逻辑代码时出现异常,JVM 创建一个异常对象,提交给异常发生的方法,这个过程被称为抛出(throw)异常。当接收到异常对象后,会寻找能处理该异常对象的 catch 块,如果找到合适的 catch 块,则把该异常对象交给该 catch 块处理,这个过程被称为捕获(catch)异常;如果找不到捕获异常的 catch 块,则程序终止。

2.1.1 语法

try {
     编写可能会出现异常的代码
} catch(异常类型  e){
     处理异常的代码
}

2.1.2 示例

public class Test {
    public static void main(String[] args) {
        System.out.println("########## 程序开始 ##########");
        try {
            System.out.println("########## 进入 try ##########");
            // 抛出异常后,直接进入 catch 中,不会执行 try 中剩余代码
            int i = 1 / 0;
            System.out.println("########## try 结束 ##########");
        } catch (Exception e) {
            System.out.println("########## 处理异常 ##########");
            e.printStackTrace();
        }
        System.out.println("########## 程序结束 ##########");
    }
}

2.1.3 注意

   try 块后可以有多个 catch 块(捕获父类异常的 catch 块必须位于捕获子类异常的后面),这是为了针对不同的异常类提供不同的异常处理方式。当系统产生不同的异常时,系统会生成不同的异常对象,根据该异常对象所属的异常类来决定使用哪个 catch 块来处理该异常。 如果 try 块被执行一次,则 try 块后只有一个 catch 块会被执行,绝不可能有多个 catch 块被执行。    try 块后的花括号{ }不可以省略,即使 try 块里只有一行代码,也不可省略这个花括号。与之类似的是,catch块后的花括号{ }也不可以省略。try 块里声明的变量是局部变量,它只在 try 块内有效,在 catch 块中不能访问该变量。

2.2 使用 finally 回收资源

   异常处理机制提供了 finally 块。不管 try 块中的代码是否出现异常,也不管哪一个 catch 块被执行,甚至在 try 块或 catch 块中执行了 return 语句,finally 块总会被执行。

2.2.1 语法

try{
     编写可能会出现异常的代码
}catch(异常类型  e){
     处理异常的代码
}finally{
     不论怎样都要执行的代码
}

2.2.2 示例

public class Test {
    public static void main(String[] args) {
        System.out.println("########## 程序开始 ##########");
        int[] arr = {1, 2, 3};
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            System.out.println(arr[3]);
        } finally {
            // 不论怎样都会执行 finally 中的代码
            System.out.println("########## finally ##########");
        }
        System.out.println("########## 程序结束 ##########");
    }
}

2.2.2 注意

   异常处理语法结构中只有 try 块是必需的,也就是说,如果没有 try 块,则不能有后面的 catch 块和 finally 块;catch 块和 finally 块都是可选的,可以同时出现,catch 块和 finally 块至少出现其中之一;不能只有 try 块,既没有 catch 块,也没有 finally 块;多个 catch 块必须位于 try 块之后,finally 块必须位于所有的 catch 块之后。


三、自定义异常

3.1 使用 throw 抛出异常

   系统是否要抛出异常,可能需要根据应用的业务需求来决定,如果程序中的数据、执行与既定的业务需求不符,这就是一种异常。由于与业务需求不符而产生的异常,必须由程序员来决定抛出,系统无法抛出这种异常。

3.1.1 语法

throw new 异常类型(参数);

3.1.2 示例

public class Test {
    public static void main(String[] args) {
        try {
            throw new ArrayIndexOutOfBoundsException("抛出了数组索引越界异常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3.2 自定义异常

   在通常情况下,异常的类名通常也包含了该异常的有用信息。所以在选择抛出异常时,应该选择合适的异常类,从而可以明确地描述该异常情况。在这种情形下,应用程序常常需要抛出自定义异常。

3.2.1 语法

   自定义异常都应该继承 Exception 基类,如果希望自定义 Runtime 异常,则应该继承 RuntimeException 基类。定义异常类时通常需要提供两个构造器:一个是无参数的构造器;另一个是带一个字符串参数的构造器,这个字符串将作为该异常对象的描述信息(也就是异常对象的 getMessage( ) 方法的返回值)。

3.2.2 示例

// 自定义异常
public class MyException extends Exception {

    public MyException() {
    }

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

---------------------------------------------------------------

// 测试类
public class Test {
    public static void main(String[] args) {
        try {
            throw new MyException("这是个自定义异常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}