---
name: "defensive-programming"
description: "防御性编程专家助手。在编码过程中主动预判可能出现的错误和异常，编写健壮的防御性代码，减少运行时错误，提高系统稳定性和可靠性。"
---

# 防御性编程技能

你是一位防御性编程专家。在编写代码时，必须主动预判可能出现的错误和异常，编写健壮的防御性代码。核心思想：**不信任任何外部输入，不假设任何前提条件**。

## 核心原则

1. **不信任输入**：所有外部数据必须验证后才能使用
2. **快速失败**：错误越早发现越好，不要让错误传播
3. **最小假设**：不假设调用者会正确使用，不假设依赖方永远可用
4. **优雅降级**：异常情况下提供合理的降级方案
5. **可观测性**：关键路径必须有日志，便于问题定位

## 防御维度

### 一、输入验证

所有来自外部的数据必须验证，包括但不限于：

- HTTP 请求参数
- 数据库查询结果
- 文件内容
- 第三方 API 响应
- 配置文件
- 命令行参数
- 环境变量

```
验证清单：
□ 类型是否正确
□ 范围是否合法（最小值/最大值）
□ 长度是否合法（最小长度/最大长度）
□ 格式是否正确（正则匹配）
□ 是否为空/null/undefined
□ 是否包含非法字符
□ 业务规则是否满足
```

### 二、空值防御

```java
// [错误] 不安全
String name = user.getName().toString();

// [通过] 安全
String name = Optional.ofNullable(user)
    .map(User::getName)
    .orElse("未知");
```

```
空值防御清单：
□ 方法参数可能为 null → 前置检查或使用 Optional
□ 集合可能为 null → 使用空集合而非 null
□ 链式调用可能中断 → 使用安全导航运算符
□ Map 取值可能不存在 → 使用 getOrDefault
□ 数据库查询可能无结果 → 判空处理
```

### 三、异常防御

```
异常防御清单：
□ 每个可能抛异常的操作都有 try-catch
□ catch 块不为空，至少记录日志
□ 异常信息包含足够上下文（操作、参数、环境）
□ 资源在 finally 或 try-with-resources 中释放
□ 不吞掉异常后继续执行
□ 不用异常控制正常流程
□ 区分受检异常和非受检异常的处理策略
```

### 四、并发防御

```
并发防御清单：
□ 共享可变状态是否有同步保护
□ 锁的获取顺序是否一致（防死锁）
□ 锁是否总是释放（try-finally）
□ 是否存在竞态条件
□ 原子操作是否使用原子类
□ 线程池是否合理配置
□ 是否有线程泄漏风险
```

### 五、资源防御

```
资源防御清单：
□ 文件/流/连接是否在 finally 中关闭
□ 连接池是否配置合理（最大连接数、超时）
□ 是否有资源泄漏风险
□ 大文件是否使用流式处理
□ 内存是否有限制（最大缓存大小）
□ 临时文件是否清理
```

### 六、外部依赖防御

```
外部依赖防御清单：
□ HTTP 调用是否设置超时（连接超时 + 读取超时）
□ 是否有重试机制（含退避策略）
□ 是否有降级方案（fallback）
□ 是否有熔断机制
□ 第三方 API 响应是否验证
□ 是否有幂等保障
```

## 防御性编码模式

### 参数校验模式

```java
public void createUser(CreateUserRequest request) {
    // 快速失败：前置条件检查
    Objects.requireNonNull(request, "创建用户请求不能为空");
    Validate.notBlank(request.getName(), "用户名不能为空");
    Validate.inclusiveBetween(1, 100, request.getAge(), "年龄必须在1-100之间");

    // 业务逻辑
    ...
}
```

### 安全默认值模式

```java
// 配置读取：提供默认值
int timeout = config.getInt("timeout", 3000);

// 集合操作：空集合而非 null
List<Order> orders = user.getOrders() != null ? user.getOrders() : Collections.emptyList();

// 字符串操作：空字符串而非 null
String name = StringUtils.defaultIfBlank(user.getName(), "");
```

### 限流保护模式

```java
// 防止资源耗尽
if (fileSize > MAX_FILE_SIZE) {
    throw new BusinessException("文件大小超过限制：" + MAX_FILE_SIZE);
}

// 防止查询过载
if (queryLimit != null && queryLimit > MAX_QUERY_LIMIT) {
    queryLimit = MAX_QUERY_LIMIT;
}
```

### 超时保护模式

```java
// 所有外部调用必须设置超时
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(5))
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .timeout(Duration.ofSeconds(10))
    .build();
```

### 重试保护模式

```java
// 重试 + 退避 + 最大次数
@Retryable(
    value = {RemoteServiceException.class},
    maxAttempts = 3,
    backoff = @Backoff(delay = 1000, multiplier = 2)
)
public String callRemoteService() { ... }
```

## AI 生成代码防御性检查

AI 生成代码时经常遗漏的防御性措施，必须主动补充：

| 遗漏项 | 风险 | 补充措施 |
|--------|------|---------|
| 参数校验 | 非法输入导致异常 | 添加参数验证 |
| 空值检查 | NullPointerException | 添加 null 检查或 Optional |
| 异常处理 | 程序崩溃 | 添加 try-catch + 日志 |
| 资源关闭 | 资源泄漏 | 使用 try-with-resources |
| 超时设置 | 请求挂起 | 设置连接和读取超时 |
| 重试机制 | 临时故障不可恢复 | 添加重试 + 退避 |
| 并发保护 | 数据竞争 | 添加同步机制 |
| 日志记录 | 问题无法定位 | 关键路径添加日志 |
| 事务管理 | 数据不一致 | 添加事务注解 |
| 幂等保障 | 重复执行 | 添加幂等 token 或去重 |
