Java基础篇-深入理解异常的抛出与处理

2132字

深入理解异常的抛出与处理

一、异常的抛出

(一)系统自动抛出异常

在程序执行过程中,当遇到一些不符合语言规则或者逻辑错误的情况时,Java 系统会自动抛出异常。例如,进行整数除法运算时,如果除数为 0,系统就会自动抛出 ArithmeticException 异常。

1
2
3
4
5
6
public class AutoThrowException {
    public static void main(String[] args) {
        int result = 10 / 0; // 这里系统会自动抛出ArithmeticException异常
        System.out.println("结果是: " + result);
    }
}

在上述代码中,10 / 0 这一操作不符合数学运算规则,Java 系统检测到这个错误后,会自动创建一个 ArithmeticException 异常对象并抛出。此时,程序的正常执行流程被打断,不会继续执行 System.out.println("结果是: " + result); 这一行代码。

(二)手动抛出异常

有时候,根据业务逻辑的需要,程序员需要手动抛出异常。这通过 throw 关键字来实现。例如,在一个用户注册功能中,要求用户名不能为空。如果检测到用户名为空,就可以手动抛出一个自定义异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class UsernameEmptyException extends RuntimeException {
    public UsernameEmptyException(String message) {
        super(message);
    }
}

public class ManualThrowException {
    public static void registerUser(String username) {
        if (username == null || username.isEmpty()) {
            throw new UsernameEmptyException("用户名不能为空");
        }
        System.out.println("用户 " + username + " 注册成功");
    }

    public static void main(String[] args) {
        try {
            registerUser("");
        } catch (UsernameEmptyException e) {
            System.out.println("捕获到异常: " + e.getMessage());
        }
    }
}

在 registerUser 方法中,通过 if 语句检查用户名是否为空。如果为空,使用 throw 关键字手动抛出一个 UsernameEmptyException 异常对象。这个异常对象携带了 “用户名不能为空” 这一错误信息。

二、异常的声明抛出

当一个方法内部可能会抛出某种异常,但该方法本身不处理这个异常,而是希望调用它的方法来处理时,就需要在方法声明中使用 throws 关键字声明该方法可能抛出的异常类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import java.io.FileNotFoundException;
import java.io.FileReader;

public class DeclareThrowException {
    // 声明该方法可能抛出FileNotFoundException异常
    public static void readFile(String filePath) throws FileNotFoundException {
        FileReader fileReader = new FileReader(filePath);
        // 如果文件不存在,FileReader构造函数会抛出FileNotFoundException异常
    }

    public static void main(String[] args) {
        try {
            readFile("nonexistentfile.txt");
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在异常: " + e.getMessage());
        }
    }
}

在 readFile 方法中,FileReader 的构造函数可能会因为文件不存在而抛出 FileNotFoundException 异常。由于 readFile 方法不处理这个异常,所以在方法声明处使用 throws FileNotFoundException 声明。这样,调用 readFile 方法的代码(如 main 方法)就需要处理这个可能抛出的异常,否则会导致编译错误。

三、异常的捕获与处理

为了避免异常导致程序终止运行,需要使用 try - catch 块来捕获并处理异常。

(一)基本的 try - catch 结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class BasicTryCatch {
    public static void main(String[] args) {
        try {
            int[] numbers = {1, 2, 3};
            System.out.println(numbers[3]); // 这里会抛出ArrayIndexOutOfBoundsException异常
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获到数组越界异常: " + e.getMessage());
        }
        System.out.println("程序继续执行...");
    }
}

在 try 块中放置可能会抛出异常的代码。如果 try 块中的代码抛出了 ArrayIndexOutOfBoundsException 异常,程序会立即跳转到对应的 catch 块中执行。catch 块中的参数 e 是捕获到的异常对象,可以通过它获取异常的相关信息,如错误消息。处理完 catch 块中的代码后,程序会继续执行 try - catch 块之后的代码。

(二)多重 catch 块

当 try 块中的代码可能抛出多种不同类型的异常时,可以使用多个 catch 块来分别处理不同类型的异常。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class MultipleCatch {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // 可能抛出ArithmeticException异常
            int[] numbers = {1, 2, 3};
            System.out.println(numbers[3]); // 可能抛出ArrayIndexOutOfBoundsException异常
        } catch (ArithmeticException e) {
            System.out.println("捕获到算术异常: " + e.getMessage());
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("捕获到数组越界异常: " + e.getMessage());
        }
        System.out.println("程序继续执行...");
    }
}

在这个例子中,try 块中的代码既有可能抛出 ArithmeticException 异常(除法运算中除数为 0),也有可能抛出 ArrayIndexOutOfBoundsException 异常(数组越界访问)。每个 catch 块负责处理特定类型的异常,程序会根据实际抛出的异常类型跳转到对应的 catch 块执行。

(三)finally 块

finally 块通常与 try - catch 块一起使用,无论 try 块中是否抛出异常,也无论异常是否被 catch 块捕获,finally 块中的代码都会被执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class FinallyBlock {
    public static void main(String[] args) {
        try {
            int result = 10 / 2;
            System.out.println("结果是: " + result);
        } catch (ArithmeticException e) {
            System.out.println("捕获到算术异常: " + e.getMessage());
        } finally {
            System.out.println("finally块总是会执行");
        }
        System.out.println("程序继续执行...");
    }
}

在上述代码中,try 块正常执行没有抛出异常,但 finally 块中的代码依然会被执行。如果 try 块中抛出了异常并且被 catch 块捕获,finally 块同样会在 catch 块执行完毕后执行。

通过理解异常的抛出、声明抛出以及捕获处理机制,可以更好地编写健壮的 Java 程序,使其能够应对各种可能出现的错误情况,提高程序的稳定性和可靠性。

如对内容有异议,请联系关邮箱2285786274@qq.com修改