场景一:CRUD 生成 | 提效 70-80% | ⭐⭐⭐⭐⭐
这是 AI 最能打的场景,没有之一。
传统写法:手写 Entity → Mapper XML → Service → ServiceImpl → Controller,一套标准的增删改查,从建表到联调,至少 40 分钟。如果加上参数校验、分页查询、统一返回体,一个小时也不夸张。
用 AI 之后:给 Cursor 一段需求描述加上数据库表结构,5-10 分钟出完整代码。而且生成的代码结构很规范------注解没漏、字段映射没错、甚至连 Swagger 文档注解都给你加上了。
但别高兴太早。
我踩过的坑:AI 生成的 CRUD 代码表面上能跑,细节经常有问题。举几个典型的:
- 字段校验粗糙------
@NotNull加了,但@Size、@Pattern这种业务校验不会主动加 - 分页查询用的是内存分页而不是数据库分页(这个坑特别隐蔽)
- 异常处理一律
catch Exception,没有细分业务异常
所以我的做法是:让 AI 先生成骨架,然后自己过一遍核心逻辑。这样比从零手写快得多,又不会因为盲信 AI 埋雷。
CRUD 是 AI 的主场,这事没争议。但你还是得 review 每一行------AI 写的 bug 比你手写的更隐蔽。
场景二:Bug 排查 | 提效 40-60% | ⭐⭐⭐⭐
先说好用的部分。
一个 NullPointerException,传统排查流程:看堆栈 → 找到报错行 → 往上追调用链 → 打断点 → 复现 → 定位 → 修复。顺利的话 15 分钟,不顺利半小时起步。
现在我直接把报错日志和相关代码丢给 Claude,通常 2-3 分钟就能给出准确定位。不仅告诉你哪里报错,还能分析为什么会走到这个分支。效率差距是数量级的。
SQL 慢查询也类似。把 EXPLAIN 结果丢给 AI,它能分析出索引缺失、全表扫描、JOIN 顺序不合理等问题,给出的优化建议大部分是靠谱的。
但是。
复杂业务逻辑的 bug------比如跨服务的数据不一致、分布式事务异常、线程安全问题------AI 基本帮不上忙。原因很简单:它不了解你的业务上下文,不知道你的系统架构长什么样,不清楚各个服务之间的调用关系。
你可以把全部代码都喂给它,但在上下文窗口有限的情况下,效果也很一般。
AI debug 像个经验丰富的实习生------标准问题秒解,但真正棘手的问题还得靠你自己。
场景三:代码重构 | 提效 30-50% | ⭐⭐⭐
这个场景我体验比较复杂,分层来说。
方法级重构------好用。 提取公共方法、消除重复代码、简化多层嵌套的 if-else,这些 AI 干得又快又好。你说一句「把这段 if-else 用策略模式重构」,它真能给你一套结构清晰的策略类出来。
模块级重构------凑合。 比如给一个老旧的 Service 类做职责拆分,AI 能给出拆分方案,但命名经常不太合适,边界划分也需要自己调整。它不太懂你的团队命名规范,也不清楚哪些逻辑在你的系统里属于同一个领域。
架构级重构------别想了。 单体拆微服务、数据库分库分表这种事,涉及太多业务决策和技术权衡,AI 给的方案顶多算个参考。你要是照着它的方案直接改,后果自负。
重构的本质是对业务的理解。AI 只能帮你搬砖,不能帮你画图纸。
场景四:写单元测试 | 提效 50-70% | ⭐⭐⭐⭐
Java 程序员最不爱写但又不能不写的东西------单元测试。
传统写法:一个 Service 方法的单测,先 mock 一堆依赖,再写正常返回用例、空值用例、异常用例,30-40 分钟很正常。而且坦白说,很多人(包括我)写单测就是为了应付覆盖率检查,质量堪忧。
现在我把 Service 代码丢给 AI,说一句「用 JUnit 5 + Mockito 生成单元测试,覆盖正常和异常场景」,3-5 分钟出一整套。
举个真实例子。比如有这么一个订单查询方法:
java
public OrderDetailVO getOrderDetail(Long orderId) {
Order order = orderMapper.selectById(orderId);
if (order == null) {
throw new BizException(ErrorCode.ORDER_NOT_FOUND);
}
// 查关联的商品信息
List<OrderItem> items = orderItemMapper.selectByOrderId(orderId);
OrderDetailVO vo = OrderConverter.toDetailVO(order);
vo.setItems(OrderConverter.toItemVOList(items));
vo.setTotalAmount(calcTotalAmount(items));
return vo;
}
AI 生成的测试长这样(节选关键部分):
java
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private OrderMapper orderMapper;
@Mock
private OrderItemMapper orderItemMapper;
@InjectMocks
private OrderServiceImpl orderService;
@Test
@DisplayName("查询存在的订单-返回完整详情")
void getOrderDetail_success() {
Order mockOrder = buildMockOrder(1001L);
List<OrderItem> mockItems = buildMockItems(1001L, 2);
when(orderMapper.selectById(1001L)).thenReturn(mockOrder);
when(orderItemMapper.selectByOrderId(1001L)).thenReturn(mockItems);
OrderDetailVO result = orderService.getOrderDetail(1001L);
assertNotNull(result);
assertEquals(1001L, result.getOrderId());
assertEquals(2, result.getItems().size());
verify(orderMapper).selectById(1001L);
}
@Test
@DisplayName("查询不存在的订单-抛出业务异常")
void getOrderDetail_notFound() {
when(orderMapper.selectById(9999L)).thenReturn(null);
BizException ex = assertThrows(BizException.class,
() -> orderService.getOrderDetail(9999L));
assertEquals(ErrorCode.ORDER_NOT_FOUND, ex.getErrorCode());
}
}
说实话,这个质量是能直接用的。Mock 层级对、断言清晰、方法命名规范。如果手写,这两个测试方法至少要 15 分钟,AI 生成只要 2 分钟。
但我手动补了什么呢?
java
@Test
@DisplayName("订单存在但商品列表为空-金额应为0")
void getOrderDetail_emptyItems() {
when(orderMapper.selectById(1001L)).thenReturn(buildMockOrder(1001L));
when(orderItemMapper.selectByOrderId(1001L)).thenReturn(Collections.emptyList());
OrderDetailVO result = orderService.getOrderDetail(1001L);
assertEquals(BigDecimal.ZERO, result.getTotalAmount());
assertTrue(result.getItems().isEmpty());
}
这种业务边界用例 ------商品列表为空时金额计算是否正确------AI 不会主动想到,因为它不知道 calcTotalAmount 对空列表的处理逻辑是不是你期望的。
AI 生成测试的优点:
- Mockito 用得很熟练,
@Mock、@InjectMocks、when().thenReturn()一气呵成 - 正常路径和基本异常覆盖得不错
- 断言写得清晰,方法命名规范
缺点也明显:
- 边界条件经常遗漏------并发场景、数据库连接异常、超时这种不会主动想到
- 有时 mock 的层级不对------该 mock Repository 的地方 mock 了 Service
- 对业务语义理解有限------不知道空列表、金额为 0 这种场景需不需要专门测
我现在的套路是:让 AI 先生成 80% 的测试用例,自己再补上那 20% 的关键边界。这比从零手写效率高太多了。
80/20 法则在 AI 写单测这件事上体现得淋漓尽致。
场景五:写技术文档 | 提效 80-90% | ⭐⭐⭐⭐⭐
这是我觉得最被低估的 AI 提效场景。
Java 程序员写代码还行,写文档真的要命。一份接口文档写半天,一份方案设计磨一整天,部署文档更是能拖就拖。
举个例子。前阵子我写了一个用户收货地址的 Controller,大概长这样:
java
@PostMapping("/address/add")
public Result<Long> addAddress(@RequestBody @Valid AddressAddReq req) { ... }
@GetMapping("/address/list")
public Result<List<AddressVO>> listAddress() { ... }
@PutMapping("/address/update")
public Result<Void> updateAddress(@RequestBody @Valid AddressUpdateReq req) { ... }
@DeleteMapping("/address/{id}")
public Result<Void> deleteAddress(@PathVariable Long id) { ... }
把这段代码丢给 AI,说「生成接口文档,Markdown 格式,包含请求参数、返回值、错误码」,2 分钟后它给我的文档(节选):
POST /address/add --- 新增收货地址
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| receiverName | String | 是 | 收货人姓名,2-20个字符 |
| phone | String | 是 | 手机号,11位 |
| province | String | 是 | 省份 |
| city | String | 是 | 城市 |
| district | String | 是 | 区/县 |
| detailAddress | String | 是 | 详细地址,最长200字符 |
| isDefault | Integer | 否 | 是否默认地址,0-否 1-是,默认0 |
返回值: Result<Long> --- 新地址ID
错误码:
ADDRESS_LIMIT_EXCEEDED--- 收货地址数量超过上限(20个)PARAM_INVALID--- 参数校验失败
它连字段的校验规则都从 @Valid 注解里推断出来了。手写这份文档至少要 30 分钟,现在 2 分钟生成,再花 5 分钟检查补充,总共不到 10 分钟。
方案设计文档也一样。给出需求描述和技术方案要点,AI 能在 10 分钟内生成一份结构完整的设计文档------背景、目标、方案对比、技术选型、风险评估,该有的都有。当然具体技术细节需要自己补,但框架已经省了你 80% 的时间。
README 就更不用说了,几乎不用改,直接能用。
如果你还在手写文档,那你是真的在浪费生命。这话可能有点绝对,但我是认真的。
我的真实结论
一张表总结
| 场景 | 提效幅度 | 推荐度 | 一句话 |
|---|---|---|---|
| CRUD 生成 | 70-80% | ⭐⭐⭐⭐⭐ | AI 的主场,没争议 |
| Bug 排查 | 40-60% | ⭐⭐⭐⭐ | 标准问题秒杀,复杂问题不行 |
| 代码重构 | 30-50% | ⭐⭐⭐ | 能搬砖不能画图纸 |
| 单元测试 | 50-70% | ⭐⭐⭐⭐ | AI 出 80% + 人工补 20% |
| 技术文档 | 80-90% | ⭐⭐⭐⭐⭐ | 最被低估的提效场景 |
关于「效率反降 19%」
最近那个「AI 写代码效率反降 19%」的研究火了,很多人拿来当 AI 没用的证据。但你仔细看就会发现:研究用的是大型开源项目(平均 110 万行代码),上下文极其复杂。
日常业务开发完全不是这个量级。我们的代码库上下文更可控,需求也更明确。在这种条件下,AI 发挥的空间大得多。
说白了,关键不是 AI 行不行,而是你选对了场景没有。用 AI 写 CRUD 能省 70% 时间,你非要让它帮你做架构设计------那确实会「提效为负」。
我的使用原则
- AI 擅长的事全交给它:CRUD、文档、测试框架、标准 bug 排查
- AI 不擅长的事别勉强:复杂业务逻辑、架构设计、跨服务问题
- 永远 review:AI 写的代码比你手写的更需要审查------因为它写的 bug 更隐蔽
- 积累自己的 Prompt:好的 Prompt 比好的工具更重要
写在最后
我是栈外,写了几年 Java,现在用 AI 多赚一份钱。
不会告诉你用 AI 就能月入十万。但它确实能让你每天省出 1-2 小时------前提是你用对场景。
下一篇聊聊这省出来的时间,我拿来干了什么。省下来的时间如果不变成钱,那提效就是个伪命题。
如果觉得有用,点个赞收个藏,后面还有更硬的干货。
这是「栈外」的第 1 篇文章。不画饼,只算账。