Java 异常处理教学

1️⃣ 什么是异常?

在 Java 中,**异常(Exception)**是程序运行时发生的错误,可能会导致程序中断。异常通常发生在:

  • 数学计算错误(如除以 0)
  • 数组访问越界
  • 文件找不到
  • 空指针访问
  • 类型转换错误等

为了保证程序的稳定性,Java 提供了异常处理机制来捕获和处理这些错误。


2️⃣ Java 异常体系

在 Java 中,异常类是 Throwable 类的子类,可以分为:

  1. Error(错误):通常是 JVM 级别的错误,不应该在代码中处理(如 OutOfMemoryError)。
  2. Exception(异常):
    • 受检异常(Checked Exception):必须在代码中处理,否则编译错误(如 IOException)。
    • 非受检异常(Unchecked Exception):程序运行时可能发生,但可以不处理(如 NullPointerException)。

Java 异常类层次结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Throwable

├── Error(错误) ❌ 一般不处理
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── ...

└── Exception(异常) ✅ 可以处理
├── 受检异常(必须处理)
│ ├── IOException
│ ├── SQLException
│ └── ...

└── 运行时异常(可选处理)
├── NullPointerException
├── ArithmeticException
├── ArrayIndexOutOfBoundsException
├── ClassCastException
└── ...

3️⃣ 异常处理语句

Java 提供了 try-catch-finally 语句来处理异常,基本语法如下:

1
2
3
4
5
6
7
try {
// 可能抛出异常的代码
} catch (异常类型 e) {
// 处理异常
} finally {
// 可选,始终执行(如释放资源)
}

3.1 try-catch 处理异常

1
2
3
4
5
6
7
8
9
10
11
public class ExceptionDemo {
public static void main(String[] args) {
try {
int result = 10 / 0; // 发生异常
System.out.println("结果:" + result);
} catch (ArithmeticException e) {
System.out.println("发生算术异常:" + e.getMessage());
}
System.out.println("程序继续执行...");
}
}

🔹 运行结果

1
2
发生算术异常:/ by zero
程序继续执行...

3.2 多个 catch 处理不同异常

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MultiCatchDemo {
public static void main(String[] args) {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[5]); // 访问越界
} catch (ArithmeticException e) {
System.out.println("算术异常:" + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组索引越界异常:" + e.getMessage());
}
System.out.println("程序继续执行...");
}
}

🔹 运行结果

1
2
数组索引越界异常:Index 5 out of bounds for length 3
程序继续执行...

3.3 多异常合并(JDK 7+)

在 Java 7 及以上版本,可以使用 | 处理多个异常:

1
2
3
4
5
6
7
8
9
public class MultiExceptionDemo {
public static void main(String[] args) {
try {
int num = Integer.parseInt("abc"); // NumberFormatException
} catch (NumberFormatException | ArithmeticException e) {
System.out.println("发生异常:" + e.getMessage());
}
}
}

3.4 finally 代码块

finally 代码块无论是否发生异常都会执行,通常用于释放资源(如关闭文件、数据库连接等)。

1
2
3
4
5
6
7
8
9
10
11
12
public class FinallyDemo {
public static void main(String[] args) {
try {
System.out.println("打开文件...");
int num = 10 / 0; // 发生异常
} catch (Exception e) {
System.out.println("发生异常:" + e.getMessage());
} finally {
System.out.println("关闭文件...");
}
}
}

🔹 运行结果

1
2
3
打开文件...
发生异常:/ by zero
关闭文件...

4️⃣ 抛出异常(throw & throws)

4.1 使用 throw 关键字

throw 用于手动抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
public class ThrowDemo {
public static void checkAge(int age) {
if (age < 18) {
throw new IllegalArgumentException("年龄必须 >= 18");
}
System.out.println("年龄合法");
}

public static void main(String[] args) {
checkAge(15); // 这里会抛异常
}
}

🔹 运行结果

1
Exception in thread "main" java.lang.IllegalArgumentException: 年龄必须 >= 18

4.2 使用 throws 声明异常

throws 用于声明方法可能抛出的异常,调用者需要处理异常。

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

public class ThrowsDemo {
public static void readFile(String filePath) throws IOException {
FileReader file = new FileReader(filePath);
BufferedReader br = new BufferedReader(file);
System.out.println(br.readLine());
br.close();
}

public static void main(String[] args) {
try {
readFile("nonexistent.txt");
} catch (IOException e) {
System.out.println("文件读取错误:" + e.getMessage());
}
}
}

🔹 运行结果

1
文件读取错误:nonexistent.txt (系统找不到指定的文件。)

5️⃣ 自定义异常

Java 允许创建自己的异常类,继承 ExceptionRuntimeException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 自定义异常类
class AgeException extends Exception {
public AgeException(String message) {
super(message);
}
}

public class CustomExceptionDemo {
public static void checkAge(int age) throws AgeException {
if (age < 18) {
throw new AgeException("未满18岁不能注册");
}
System.out.println("注册成功!");
}

public static void main(String[] args) {
try {
checkAge(16);
} catch (AgeException e) {
System.out.println("异常:" + e.getMessage());
}
}
}

🔹 运行结果

1
异常:未满18岁不能注册

6️⃣ 异常处理最佳实践

只捕获必要的异常,不要用 catch(Exception e) 捕获所有异常
合理使用 finally 释放资源
使用自定义异常提高可读性
受检异常(Checked Exception)应该处理或声明
运行时异常(Unchecked Exception)一般不捕获,避免隐藏 bug


🎯 练习题

1️⃣ 编写一个方法,计算两个数的除法,如果除数为 0,抛出 ArithmeticException
2️⃣ 编写一个读取文件的程序,如果文件不存在,抛出 FileNotFoundException 并处理它。
3️⃣ 创建自定义异常NegativeNumberException,如果方法参数是负数,则抛出异常。


💡 试试动手写代码吧!有问题随时交流 😊🚀