前言

异常处理是Java编程中不可或缺的重要机制,它帮助我们处理程序运行过程中可能出现的各种错误情况。良好的异常处理不仅可以提高程序的健壮性和用户体验,还能帮助开发者快速定位和解决问题。理解异常的本质、分类和处理方式,是编写高质量Java程序的必备技能。本文将全面介绍Java异常处理的各个方面,帮助您掌握这一重要的编程概念。

异常基础概念

什么是异常

异常(Exception)是程序执行过程中发生的中断正常指令流的事件。当程序运行时遇到无法处理的情况时,就会产生异常。Java通过异常机制提供了一种结构化的错误处理方式。

异常的层次结构

graph TD
    A[Throwable] --> B[Error]
    A --> C[Exception]
    
    B --> B1[OutOfMemoryError]
    B --> B2[StackOverflowError]
    B --> B3[NoClassDefFoundError]
    
    C --> C1[RuntimeException 运行时异常]
    C --> C2[非RuntimeException 编译时异常]
    
    C1 --> C11[NullPointerException]
    C1 --> C12[ArrayIndexOutOfBoundsException]
    C1 --> C13[ClassCastException]
    C1 --> C14[NumberFormatException]
    C1 --> C15[IllegalArgumentException]
    
    C2 --> C21[IOException]
    C2 --> C22[ClassNotFoundException]
    C2 --> C23[SQLException]
    C2 --> C24[FileNotFoundException]
    
    D[异常分类] --> D1[受检异常 Checked]
    D --> D2[非受检异常 Unchecked]
    
    D1 --> D11[编译时必须处理]
    D1 --> D12[继承自Exception但非RuntimeException]
    
    D2 --> D21[运行时异常]
    D2 --> D22[Error类异常]

异常的特点

  • 异常是对象:所有异常都是Throwable类的子类实例
  • 异常具有传播性:未处理的异常会向上传播直到被捕获或程序终止
  • 异常包含信息:异常对象包含错误信息、堆栈跟踪等调试信息
  • 异常可以被处理:通过try-catch机制可以捕获和处理异常

异常的分类

Error类异常

Error类异常表示严重的系统级错误,通常无法恢复,程序应该终止:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ErrorDemo {
public static void main(String[] args) {
// StackOverflowError示例
recursiveMethod();
}

public static void recursiveMethod() {
// 无限递归会导致栈溢出
recursiveMethod();
}

public static void outOfMemoryExample() {
// OutOfMemoryError示例
List<int[]> memoryLeak = new ArrayList<>();
while (true) {
memoryLeak.add(new int[1000000]);
}
}
}

运行时异常(RuntimeException)

运行时异常是程序逻辑错误导致的异常,可以通过修改代码避免:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class RuntimeExceptionDemo {
public static void main(String[] args) {
// NullPointerException示例
String str = null;
try {
int length = str.length(); // 空指针异常
} catch (NullPointerException e) {
System.out.println("空指针异常:" + e.getMessage());
}

// ArrayIndexOutOfBoundsException示例
int[] arr = {1, 2, 3};
try {
int value = arr[10]; // 数组越界
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常:" + e.getMessage());
}

// NumberFormatException示例
try {
int num = Integer.parseInt("abc"); // 数字格式异常
} catch (NumberFormatException e) {
System.out.println("数字格式异常:" + e.getMessage());
}

// ClassCastException示例
try {
Object obj = "Hello";
Integer num = (Integer) obj; // 类型转换异常
} catch (ClassCastException e) {
System.out.println("类型转换异常:" + e.getMessage());
}
}
}

编译时异常(Checked Exception)

编译时异常必须在编译时处理,否则无法通过编译:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.*;
import java.sql.*;

public class CheckedExceptionDemo {
// IOException示例
public void readFile(String filename) throws IOException {
FileReader file = new FileReader(filename);
BufferedReader reader = new BufferedReader(file);
String line = reader.readLine();
reader.close();
}

// ClassNotFoundException示例
public void loadClass(String className) throws ClassNotFoundException {
Class<?> clazz = Class.forName(className);
System.out.println("加载类:" + clazz.getName());
}

// SQLException示例
public void connectDatabase() throws SQLException {
// 模拟数据库连接
throw new SQLException("数据库连接失败");
}

public static void main(String[] args) {
CheckedExceptionDemo demo = new CheckedExceptionDemo();

// 必须处理编译时异常
try {
demo.readFile("test.txt");
demo.loadClass("com.example.MyClass");
demo.connectDatabase();
} catch (IOException e) {
System.out.println("IO异常:" + e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println("类未找到异常:" + e.getMessage());
} catch (SQLException e) {
System.out.println("SQL异常:" + e.getMessage());
}
}
}

try-catch-finally语句

基本语法

graph TD
    A[try块] --> B{是否发生异常?}
    B -->|是| C[catch块]
    B -->|否| D[finally块]
    C --> D
    D --> E[程序继续执行]
    
    F[异常处理流程] --> F1[try中发生异常]
    F1 --> F2[寻找匹配的catch块]
    F2 --> F3[执行catch块代码]
    F3 --> F4[执行finally块]
    F4 --> F5[继续执行或重新抛出]
    
    G[多catch块匹配规则] --> G1[从上到下匹配]
    G --> G2[子类异常在前]
    G --> G3[父类异常在后]
    G --> G4[只执行第一个匹配的catch]

详细示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import java.io.*;

public class TryCatchFinallyDemo {
public static void main(String[] args) {
// 基本try-catch结构
basicTryCatch();

// 多catch块处理
multipleCatch();

// try-catch-finally结构
tryCatchFinally();

// try-with-resources结构
tryWithResources();
}

// 基本try-catch结构
public static void basicTryCatch() {
System.out.println("=== 基本try-catch示例 ===");
try {
int result = 10 / 0; // 会抛出ArithmeticException
System.out.println("结果:" + result);
} catch (ArithmeticException e) {
System.out.println("捕获到算术异常:" + e.getMessage());
e.printStackTrace(); // 打印堆栈跟踪
}
System.out.println("程序继续执行\n");
}

// 多catch块处理
public static void multipleCatch() {
System.out.println("=== 多catch块示例 ===");
String[] arr = {"100", "abc", null};

for (int i = 0; i < arr.length; i++) {
try {
String str = arr[i];
int length = str.length(); // 可能抛出NullPointerException
int num = Integer.parseInt(str); // 可能抛出NumberFormatException
System.out.println("解析成功:" + num);
} catch (NullPointerException e) {
System.out.println("空指针异常:字符串为null");
} catch (NumberFormatException e) {
System.out.println("数字格式异常:无法解析为数字");
} catch (Exception e) {
System.out.println("其他异常:" + e.getMessage());
}
}
System.out.println();
}

// try-catch-finally结构
public static void tryCatchFinally() {
System.out.println("=== try-catch-finally示例 ===");
FileInputStream fis = null;
try {
fis = new FileInputStream("nonexistent.txt");
// 文件操作代码
} catch (FileNotFoundException e) {
System.out.println("文件未找到:" + e.getMessage());
} catch (IOException e) {
System.out.println("IO异常:" + e.getMessage());
} finally {
// finally块总是执行,用于清理资源
System.out.println("执行finally块:清理资源");
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
System.out.println("关闭文件时发生异常:" + e.getMessage());
}
}
}
System.out.println();
}

// try-with-resources结构(Java 7+)
public static void tryWithResources() {
System.out.println("=== try-with-resources示例 ===");
// 自动资源管理,无需手动关闭
try (FileInputStream fis = new FileInputStream("test.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {

String line = reader.readLine();
System.out.println("读取到:" + line);

} catch (FileNotFoundException e) {
System.out.println("文件未找到:" + e.getMessage());
} catch (IOException e) {
System.out.println("IO异常:" + e.getMessage());
}
// 资源会自动关闭,无需finally块
System.out.println();
}
}

throws和throw关键字

throws声明异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.io.*;

public class ThrowsDemo {
// 方法声明抛出异常
public void readFile(String filename) throws IOException, FileNotFoundException {
if (filename == null) {
throw new IllegalArgumentException("文件名不能为null");
}

FileReader file = new FileReader(filename); // 可能抛出FileNotFoundException
BufferedReader reader = new BufferedReader(file); // 可能抛出IOException

try {
String line = reader.readLine();
System.out.println("读取到:" + line);
} finally {
reader.close();
}
}

// 多层异常传播
public void processFile(String filename) throws IOException {
readFile(filename); // 传播IOException
}

public void handleFile(String filename) {
try {
processFile(filename);
} catch (IOException e) {
System.out.println("处理文件时发生异常:" + e.getMessage());
}
}

public static void main(String[] args) {
ThrowsDemo demo = new ThrowsDemo();
demo.handleFile("test.txt");
}
}

throw主动抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class ThrowDemo {
// 验证年龄方法
public void validateAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数:" + age);
}
if (age > 150) {
throw new IllegalArgumentException("年龄不能超过150:" + age);
}
System.out.println("年龄验证通过:" + age);
}

// 银行取款方法
public void withdraw(double amount, double balance) throws InsufficientFundsException {
if (amount <= 0) {
throw new IllegalArgumentException("取款金额必须大于0");
}
if (amount > balance) {
throw new InsufficientFundsException("余额不足,余额:" + balance + ",取款:" + amount);
}
System.out.println("取款成功,金额:" + amount);
}

// 数组访问方法
public int getArrayElement(int[] arr, int index) {
if (arr == null) {
throw new NullPointerException("数组不能为null");
}
if (index < 0 || index >= arr.length) {
throw new ArrayIndexOutOfBoundsException("索引越界:" + index + ",数组长度:" + arr.length);
}
return arr[index];
}

public static void main(String[] args) {
ThrowDemo demo = new ThrowDemo();

// 测试年龄验证
try {
demo.validateAge(-5);
} catch (IllegalArgumentException e) {
System.out.println("年龄验证异常:" + e.getMessage());
}

// 测试银行取款
try {
demo.withdraw(1000, 500);
} catch (InsufficientFundsException e) {
System.out.println("取款异常:" + e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("参数异常:" + e.getMessage());
}

// 测试数组访问
try {
int[] arr = {1, 2, 3};
int value = demo.getArrayElement(arr, 5);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组访问异常:" + e.getMessage());
}
}
}

自定义异常

创建自定义异常类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// 自定义受检异常
public class InsufficientFundsException extends Exception {
private double amount;
private double balance;

public InsufficientFundsException() {
super("余额不足");
}

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

public InsufficientFundsException(double amount, double balance) {
super("余额不足:尝试取款" + amount + ",当前余额" + balance);
this.amount = amount;
this.balance = balance;
}

public InsufficientFundsException(String message, Throwable cause) {
super(message, cause);
}

public double getAmount() { return amount; }
public double getBalance() { return balance; }
public double getShortfall() { return amount - balance; }
}

// 自定义运行时异常
public class InvalidUserInputException extends RuntimeException {
private String inputValue;
private String expectedFormat;

public InvalidUserInputException(String inputValue, String expectedFormat) {
super("无效输入:'" + inputValue + "',期望格式:" + expectedFormat);
this.inputValue = inputValue;
this.expectedFormat = expectedFormat;
}

public InvalidUserInputException(String message, String inputValue, String expectedFormat) {
super(message);
this.inputValue = inputValue;
this.expectedFormat = expectedFormat;
}

public String getInputValue() { return inputValue; }
public String getExpectedFormat() { return expectedFormat; }
}

// 业务异常基类
public abstract class BusinessException extends Exception {
private String errorCode;
private String errorMessage;

public BusinessException(String errorCode, String errorMessage) {
super(errorMessage);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}

public BusinessException(String errorCode, String errorMessage, Throwable cause) {
super(errorMessage, cause);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}

public String getErrorCode() { return errorCode; }
public String getErrorMessage() { return errorMessage; }

@Override
public String toString() {
return String.format("[%s] %s", errorCode, errorMessage);
}
}

// 具体业务异常
public class UserNotFoundException extends BusinessException {
private String userId;

public UserNotFoundException(String userId) {
super("USER_NOT_FOUND", "用户不存在:" + userId);
this.userId = userId;
}

public String getUserId() { return userId; }
}

public class ProductOutOfStockException extends BusinessException {
private String productId;
private int requestedQuantity;
private int availableQuantity;

public ProductOutOfStockException(String productId, int requestedQuantity, int availableQuantity) {
super("PRODUCT_OUT_OF_STOCK",
String.format("商品库存不足 - 商品ID:%s,请求数量:%d,可用数量:%d",
productId, requestedQuantity, availableQuantity));
this.productId = productId;
this.requestedQuantity = requestedQuantity;
this.availableQuantity = availableQuantity;
}

public String getProductId() { return productId; }
public int getRequestedQuantity() { return requestedQuantity; }
public int getAvailableQuantity() { return availableQuantity; }
}

使用自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.util.HashMap;
import java.util.Map;

public class CustomExceptionDemo {
private Map<String, Double> accounts;
private Map<String, Integer> inventory;

public CustomExceptionDemo() {
accounts = new HashMap<>();
accounts.put("user001", 1000.0);
accounts.put("user002", 2500.0);

inventory = new HashMap<>();
inventory.put("PROD001", 50);
inventory.put("PROD002", 0);
}

// 银行账户操作
public void withdraw(String accountId, double amount) throws InsufficientFundsException {
Double balance = accounts.get(accountId);
if (balance == null) {
throw new IllegalArgumentException("账户不存在:" + accountId);
}

if (amount <= 0) {
throw new InvalidUserInputException(String.valueOf(amount), "正数金额");
}

if (amount > balance) {
throw new InsufficientFundsException(amount, balance);
}

accounts.put(accountId, balance - amount);
System.out.printf("取款成功 - 账户:%s,金额:%.2f,余额:%.2f%n",
accountId, amount, balance - amount);
}

// 商品购买操作
public void purchaseProduct(String productId, int quantity)
throws ProductOutOfStockException, UserNotFoundException {
Integer stock = inventory.get(productId);
if (stock == null) {
throw new IllegalArgumentException("商品不存在:" + productId);
}

if (quantity <= 0) {
throw new InvalidUserInputException(String.valueOf(quantity), "正整数数量");
}

if (quantity > stock) {
throw new ProductOutOfStockException(productId, quantity, stock);
}

inventory.put(productId, stock - quantity);
System.out.printf("购买成功 - 商品:%s,数量:%d,剩余库存:%d%n",
productId, quantity, stock - quantity);
}

public static void main(String[] args) {
CustomExceptionDemo demo = new CustomExceptionDemo();

// 测试银行取款
System.out.println("=== 银行取款测试 ===");
try {
demo.withdraw("user001", 500.0); // 成功
demo.withdraw("user001", 800.0); // 余额不足
} catch (InsufficientFundsException e) {
System.out.println("取款失败:" + e.getMessage());
System.out.println("缺口金额:" + e.getShortfall());
} catch (InvalidUserInputException e) {
System.out.println("输入无效:" + e.getMessage());
} catch (IllegalArgumentException e) {
System.out.println("参数错误:" + e.getMessage());
}

// 测试商品购买
System.out.println("\n=== 商品购买测试 ===");
try {
demo.purchaseProduct("PROD001", 30); // 成功
demo.purchaseProduct("PROD001", 30); // 库存不足
} catch (ProductOutOfStockException e) {
System.out.println("购买失败:" + e);
System.out.println("商品ID:" + e.getProductId());
System.out.println("请求数量:" + e.getRequestedQuantity());
System.out.println("可用数量:" + e.getAvailableQuantity());
} catch (UserNotFoundException e) {
System.out.println("用户异常:" + e);
} catch (InvalidUserInputException e) {
System.out.println("输入异常:" + e.getMessage());
}
}
}

异常处理最佳实践

异常处理原则

graph TD
    A[异常处理最佳实践] --> B[捕获具体异常]
    A --> C[合理的异常粒度]
    A --> D[及时释放资源]
    A --> E[记录异常信息]
    A --> F[不要忽略异常]
    A --> G[性能考虑]
    
    B --> B1[避免捕获Exception]
    B --> B2[按照从具体到抽象的顺序]
    B --> B3[针对性处理不同异常]
    
    C --> C1[不要过度使用异常]
    C --> C2[异常用于异常情况]
    C --> C3[正常流程不依赖异常]
    
    D --> D1[使用try-with-resources]
    D --> D2[finally块中释放资源]
    D --> D3[避免资源泄漏]
    
    E --> E1[记录异常堆栈]
    E --> E2[包含上下文信息]
    E --> E3[便于问题定位]
    
    F --> F1[空catch块是禁忌]
    F --> F2[至少记录日志]
    F --> F3[考虑恢复策略]
    
    G --> G1[异常创建有开销]
    G --> G2[避免在循环中抛异常]
    G --> G3[缓存常用异常]

实践示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import java.io.*;
import java.util.logging.Logger;
import java.util.logging.Level;

public class ExceptionBestPractices {
private static final Logger logger = Logger.getLogger(ExceptionBestPractices.class.getName());

// 1. 捕获具体异常,而非通用异常
public void goodExceptionHandling(String filename) {
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line = reader.readLine();
processLine(line);
} catch (FileNotFoundException e) {
logger.log(Level.WARNING, "文件未找到:" + filename, e);
// 针对性处理:提示用户检查文件路径
} catch (SecurityException e) {
logger.log(Level.SEVERE, "没有读取文件权限:" + filename, e);
// 针对性处理:提示用户检查权限
} catch (IOException e) {
logger.log(Level.SEVERE, "读取文件时发生IO异常:" + filename, e);
// 针对性处理:可能的网络或磁盘问题
}
}

// 2. 错误的异常处理方式(避免这样做)
public void badExceptionHandling(String filename) {
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
processLine(line);
reader.close();
} catch (Exception e) {
// 错误:捕获过于宽泛的异常
// 错误:空catch块
}
}

// 3. 资源管理最佳实践
public String readFileContent(String filename) throws IOException {
StringBuilder content = new StringBuilder();

// 使用try-with-resources自动管理资源
try (FileInputStream fis = new FileInputStream(filename);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader reader = new BufferedReader(isr)) {

String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}

} catch (FileNotFoundException e) {
logger.log(Level.WARNING, "文件不存在:" + filename, e);
throw e; // 重新抛出,让调用者处理
} catch (UnsupportedEncodingException e) {
logger.log(Level.SEVERE, "不支持的编码:UTF-8", e);
throw e;
} catch (IOException e) {
logger.log(Level.SEVERE, "读取文件失败:" + filename, e);
throw e;
}

return content.toString();
}

// 4. 异常转换和包装
public void convertException(String data) throws DataProcessingException {
try {
processData(data);
} catch (NumberFormatException e) {
// 将底层异常转换为业务异常
throw new DataProcessingException("数据格式错误:" + data, e);
} catch (NullPointerException e) {
throw new DataProcessingException("数据为空", e);
}
}

// 5. 性能友好的异常处理
public void performanceConsciousMethod(String[] data) {
for (String item : data) {
// 避免在循环中频繁抛出异常
if (item == null || item.trim().isEmpty()) {
logger.warning("跳过无效数据项");
continue; // 使用正常流程控制,而非异常
}

try {
processValidData(item);
} catch (DataProcessingException e) {
// 记录异常但继续处理其他数据
logger.log(Level.WARNING, "处理数据项失败:" + item, e);
}
}
}

// 6. 异常信息的记录和报告
public void comprehensiveExceptionLogging() {
try {
riskyOperation();
} catch (Exception e) {
// 记录完整的上下文信息
logger.log(Level.SEVERE,
String.format("操作失败 - 时间:%s,用户:%s,操作:%s",
new java.util.Date(), getCurrentUser(), "riskyOperation"), e);

// 如果需要,发送错误报告
sendErrorReport(e);

// 执行清理操作
cleanup();
}
}

// 辅助方法
private void processLine(String line) throws DataProcessingException {
if (line == null) {
throw new DataProcessingException("行数据为空");
}
// 处理逻辑
}

private void processData(String data) throws NumberFormatException {
Integer.parseInt(data);
}

private void processValidData(String data) throws DataProcessingException {
// 处理逻辑
}

private void riskyOperation() throws Exception {
// 可能失败的操作
}

private String getCurrentUser() {
return "currentUser";
}

private void sendErrorReport(Exception e) {
// 发送错误报告的逻辑
}

private void cleanup() {
// 清理资源的逻辑
}
}

// 自定义业务异常
class DataProcessingException extends Exception {
public DataProcessingException(String message) {
super(message);
}

public DataProcessingException(String message, Throwable cause) {
super(message, cause);
}
}

异常链和异常抑制

异常链(Exception Chaining)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class ExceptionChainingDemo {
public void databaseOperation() throws DatabaseException {
try {
connectToDatabase();
} catch (SQLException e) {
// 包装底层异常,保持异常链
throw new DatabaseException("数据库操作失败", e);
}
}

public void businessLogic() throws BusinessLogicException {
try {
databaseOperation();
} catch (DatabaseException e) {
// 继续包装,形成异常链
throw new BusinessLogicException("业务逻辑执行失败", e);
}
}

private void connectToDatabase() throws SQLException {
throw new SQLException("连接数据库失败:网络超时");
}

public static void main(String[] args) {
ExceptionChainingDemo demo = new ExceptionChainingDemo();
try {
demo.businessLogic();
} catch (BusinessLogicException e) {
System.out.println("顶层异常:" + e.getMessage());

// 遍历异常链
Throwable cause = e.getCause();
while (cause != null) {
System.out.println("原因:" + cause.getMessage());
cause = cause.getCause();
}

// 打印完整的堆栈跟踪
e.printStackTrace();
}
}
}

class DatabaseException extends Exception {
public DatabaseException(String message, Throwable cause) {
super(message, cause);
}
}

class BusinessLogicException extends Exception {
public BusinessLogicException(String message, Throwable cause) {
super(message, cause);
}
}

异常抑制(Suppressed Exceptions)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class SuppressedExceptionDemo {
public void demonstrateSuppressedException() {
try (CloseableResource resource1 = new CloseableResource("Resource1");
CloseableResource resource2 = new CloseableResource("Resource2")) {

// 模拟业务逻辑中的异常
throw new RuntimeException("业务逻辑异常");

} catch (Exception e) {
System.out.println("主异常:" + e.getMessage());

// 获取被抑制的异常
Throwable[] suppressed = e.getSuppressed();
for (Throwable t : suppressed) {
System.out.println("抑制的异常:" + t.getMessage());
}
}
}

public static void main(String[] args) {
new SuppressedExceptionDemo().demonstrateSuppressedException();
}
}

class CloseableResource implements AutoCloseable {
private String name;

public CloseableResource(String name) {
this.name = name;
System.out.println("创建资源:" + name);
}

@Override
public void close() throws Exception {
System.out.println("关闭资源:" + name);
// 模拟关闭时的异常
throw new RuntimeException("关闭资源时异常:" + name);
}
}

总结

Java异常处理机制是程序健壮性的重要保障,本文全面介绍了异常处理的各个方面:

  1. 异常基础:理解异常的概念、层次结构和分类
  2. 异常类型:掌握Error、运行时异常和编译时异常的区别
  3. 处理机制:熟练使用try-catch-finally和try-with-resources
  4. 异常传播:理解throws声明和throw抛出的使用
  5. 自定义异常:学会创建和使用业务相关的自定义异常
  6. 最佳实践:掌握异常处理的原则和性能考虑
  7. 高级特性:了解异常链和异常抑制机制

良好的异常处理不仅能提高程序的稳定性,还能为用户提供更好的体验,为开发者提供有效的调试信息。在实际开发中,应该根据具体场景选择合适的异常处理策略,既要保证程序的健壮性,也要考虑性能和可维护性。

参考资料

  1. Oracle Java Documentation - Exception Handling
  2. Effective Java by Joshua Bloch - Exception Handling
  3. Java核心技术卷I - 异常处理
  4. Clean Code by Robert Martin - Error Handling
    abbrlink: 2