一、基本概念
在 Java 中,异常处理是一种重要的编程概念,用于处理程序执行过程中可能出现的错误或异常情况。
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error,如果你用 System.out.println(11/0),那么你是因为你用 0 做了除数,会抛出 java.lang.ArithmeticException 的异常。
异常发生的原因有很多,通常包含以下几大类:
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断,或者JVM内存溢出。
这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。
要理解 Java 异常处理是如何工作的,你需要掌握以下三种类型的异常:
-
检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这些异常在编译时强制要求程序员处理。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
这类异常通常使用 try-catch 块来捕获并处理异常,或者在方法声明中使用 throws 子句声明方法可能抛出的异常。
try {
// 可能会抛出异常的代码
} catch (IOException e) {
// 处理异常的代码
}
或者:
public void readFile() throws IOException {
// 可能会抛出IOException的代码
}
运行时异常: 这些异常在编译时不强制要求处理,通常是由程序中的错误引起的,例如 NullPointerException、ArrayIndexOutOfBoundsException 等,这类异常可以选择处理,但并非强制要求。
try {
// 可能会抛出异常的代码
} catch (NullPointerException e) {
// 处理异常的代码
}
-
错误: 错误不是异常,而是脱离程序员控制的问题,错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Java 提供了以下关键字和类来支持异常处理:
- try:用于包裹可能会抛出异常的代码块。
- catch:用于捕获异常并处理异常的代码块。
- finally:用于包含无论是否发生异常都需要执行的代码块。
- throw:用于手动抛出异常。
- throws:用于在方法声明中指定方法可能抛出的异常。
- Exception类:是所有异常类的父类,它提供了一些方法来获取异常信息,如 getMessage()、printStackTrace() 等。
二、使用try catch
用于处理可能出现的算术异常:
public class Main
{
public static void main(String[] args) {
try {
int a = 10;
int b = 0;
int result = a / b; // 这里可能会出现除数为0的算术异常
System.out.println("结果是:" + result);
} catch (ArithmeticException e) { // 捕获算术异常
System.out.println("发生了算术异常:" + e.getMessage());
} finally { // 无论是否捕获到异常,finally块中的代码都会执行
System.out.println("finally块执行了");
}
System.out.println("程序继续执行");
}
}
三、多重捕获块
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。
多重捕获块的语法如下所示:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型3 异常的变量名3){
// 程序代码
}
上面的代码段包含了 3 个 catch块。
可以在 try 语句后面添加任意数量的 catch 块。
如果保护代码中发生异常,异常被抛给第一个 catch 块。
如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。
如果不匹配,它会被传递给第二个 catch 块。
如此,直到异常被捕获或者通过所有的 catch 块。
四、throws/throw 关键字
在Java中, throw 和 throws 关键字是用于处理异常的。
throw 关键字用于在代码中抛出异常,而 throws 关键字用于在方法声明中指定可能会抛出的异常类型。
throw 关键字
throw 关键字用于在当前方法中抛出一个异常。通常情况下,当代码执行到某个条件下无法继续正常执行时,可以使用 throw 关键字抛出异常,以告知调用者当前代码的执行状态。
例如,下面的代码中,在方法中判断 num 是否小于 0,如果是,则抛出一个 IllegalArgumentException 异常。
public void checkNumber(int num) {
if (num < 0) {
throw new IllegalArgumentException("Number must be positive");
}
}
throws 关键字
throws 关键字用于在方法声明中指定该方法可能抛出的异常。当方法内部抛出指定类型的异常时,该异常会被传递给调用该方法的代码,并在该代码中处理异常。
例如,下面的代码中,当 readFile 方法内部发生 IOException 异常时,会将该异常传递给调用该方法的代码。在调用该方法的代码中,必须捕获或声明处理 IOException 异常。
public void readFile(String filePath) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
}
五、finally关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
finally 代码块出现在 catch 代码块最后,语法如下:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
六、try-with-resources
JDK7 之后,Java 新增的 try-with-resource 语法结构,旨在自动管理资源,确保资源在使用后能够及时关闭,避免资源泄露 。try-with-resources 是一种异常处理机制,它能够自动关闭在 try 块中声明的资源,无需显式地在 finally 块中关闭。
在 try-with-resources 语句中,你只需要在 try 关键字后面声明资源,然后跟随一个代码块。无论代码块中的操作是否成功,资源都会在 try 代码块执行完毕后自动关闭。