37、重构工具实战(一):IDE自动重构功能(IntelliJ IDEA / VS Code)
说实话,很多程序员对重构有误解。觉得重构就是大动干戈,得专门排个迭代来做。其实不然。真正的高手,是把重构融入日常编码中的。怎么做到?靠的就是IDE的自动重构功能。
我刚开始带团队的时候,发现一个现象:新人改代码,经常是手动改完一个变量名,再满文件搜另一个。改完还提心吊胆,生怕漏了哪里。我当时就说:你们这是用记事本写代码呢?IDE给你准备了那么多快捷键,怎么不用?
今天我们就来聊聊,IntelliJ IDEA和VS Code里那些能让你「闭着眼」重构的功能。说白了,就是让工具替你干脏活累活。
重命名:最基础也最常用
重命名是所有重构操作里,我使用频率最高的一个。没有之一。
你想想看,一个项目写久了,变量名、函数名、类名,总有不满意的时候。手动改?太容易漏了。尤其是JavaScript这种动态语言,改个变量名,可能关联了十几个文件。
在IntelliJ IDEA里,重命名的快捷键是 Shift + F6。选中一个符号,按一下,输入新名字,回车。所有引用这个符号的地方,全部自动更新。包括注释里的引用,它都能识别。
VS Code里对应的是 F2。选中符号,按F2,输入新名字,回车。效果一样。
提取方法/函数:告别长函数
长函数是代码坏味道的重灾区。我见过一个函数写了800行,里面什么都有:数据库查询、业务逻辑、UI渲染、日志打印……读这种代码,简直是在考古。
怎么治?提取方法。
在IntelliJ IDEA里,选中一段代码,按 Ctrl + Alt + M(Windows/Linux)或 Cmd + Option + M(Mac),IDE会自动帮你创建一个新方法。它会自动分析这段代码用了哪些局部变量,哪些需要作为参数传入,哪些可以作为返回值。你只需要给新方法起个名字就行。
VS Code里,选中代码后右键,选择「Refactor」→「Extract Function」,或者直接用快捷键 Ctrl + Shift + R(需要安装扩展)。
// 重构前
public void processOrder(Order order) {
// 验证订单
if (order.getItems() == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("订单不能为空");
}
if (order.getTotalPrice() <= 0) {
throw new IllegalArgumentException("订单金额必须大于0");
}
// 计算折扣
double discount = 0;
if (order.getTotalPrice() > 1000) {
discount = 0.1;
} else if (order.getTotalPrice() > 500) {
discount = 0.05;
}
// 保存订单
order.setDiscount(discount);
orderRepository.save(order);
}
// 重构后
public void processOrder(Order order) {
validateOrder(order);
double discount = calculateDiscount(order);
saveOrder(order, discount);
}
private void validateOrder(Order order) {
if (order.getItems() == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("订单不能为空");
}
if (order.getTotalPrice() <= 0) {
throw new IllegalArgumentException("订单金额必须大于0");
}
}
private double calculateDiscount(Order order) {
if (order.getTotalPrice() > 1000) {
return 0.1;
} else if (order.getTotalPrice() > 500) {
return 0.05;
}
return 0;
}
private void saveOrder(Order order, double discount) {
order.setDiscount(discount);
orderRepository.save(order);
}
提取变量/常量:消除魔法数字
代码里直接写数字、字符串,是新手最爱犯的毛病。比如 if (status == 3),3是什么?没人知道。得去翻文档、问同事。
用IDE的提取变量功能,可以快速解决这个问题。
在IntelliJ IDEA里,选中一个表达式,按 Ctrl + Alt + V,IDE会帮你创建一个变量,并用这个变量替换所有相同的表达式。如果你选中的是一个常量值,还可以选择提取为常量(Ctrl + Alt + C)。
VS Code里,选中表达式后,右键「Refactor」→「Extract to constant」或「Extract to variable」。
// 重构前
if (order.getStatus() == 3) {
// 已发货
}
// 重构后
private static final int ORDER_STATUS_SHIPPED = 3;
if (order.getStatus() == ORDER_STATUS_SHIPPED) {
// 已发货
}
ArrayList 时,我建议手动改成 List。IDE不会替你思考设计层面的东西,它只负责机械操作。
内联:反向操作也很有用
有提取,就有内联。内联是提取的反向操作。什么时候用?
比如你发现某个变量只被使用了一次,那这个变量就是多余的。直接内联掉,代码更简洁。或者某个方法体只有一行,而且只被调用了一次,也可以内联掉。
在IntelliJ IDEA里,选中变量或方法调用,按 Ctrl + Alt + N。VS Code里,选中后右键「Refactor」→「Inline variable」或「Inline function」。
// 内联前
String userName = user.getName();
System.out.println("Hello, " + userName);
// 内联后
System.out.println("Hello, " + user.getName());
移动和复制:调整代码结构
项目大了,类的位置经常需要调整。比如把某个工具类从 utils 包移到 common 包。手动移动?那所有引用这个类的地方都得改import。
用IDE的移动功能:在IntelliJ IDEA里,选中类名,按 F6,选择目标包,IDE会自动更新所有引用。VS Code里,右键「Refactor」→「Move to file」。
复制功能(F5)则适合用来创建相似类。比如你有一个 UserService,现在要创建一个 AdminService,大部分逻辑类似。复制一份,再改差异,比从头写快得多。
签名变更:改方法参数不再头疼
改方法签名,是重构里风险比较高的操作。尤其是当这个方法被很多地方调用时,改一个参数名、增删一个参数,都可能引发编译错误。
IDE的「Change Signature」功能就是为此设计的。在IntelliJ IDEA里,选中方法名,按 Ctrl + F6。你可以自由增删参数、调整顺序、改参数名。IDE会自动更新所有调用点,并且会提示你哪些地方需要手动处理(比如新参数没有默认值)。
VS Code里,这个功能需要安装扩展(比如「P42」或「JavaScript Refactor」),原生支持较弱。
知识体系总览
下面这张图,是我对IDE自动重构功能的一个梳理。你可以把它当作一个速查表。
安全删除:别怕删代码
很多程序员不敢删代码,怕删了不该删的东西。其实IDE提供了「安全删除」功能。
在IntelliJ IDEA里,选中一个符号(类、方法、变量),按 Alt + Delete。IDE会先检查这个符号是否被任何地方引用。如果有引用,它会列出所有引用点,让你确认。只有确认没有引用后,才会真正删除。
这个功能我经常用来清理死代码。项目迭代久了,总会积累一些废弃的方法、类。用安全删除扫一遍,能清理掉不少垃圾。
总结一下
IDE的自动重构功能,说白了就是让你把精力集中在「改什么」上,而不是「怎么改」上。重命名、提取方法、提取变量、内联、移动、签名变更、安全删除——这七个功能,覆盖了日常重构90%的场景。
我个人建议,花一个下午的时间,把这些快捷键练熟。练到手指形成肌肉记忆。以后写代码,遇到坏味道,顺手就重构了。不用犹豫,不用纠结。工具就在那里,用就是了。
下一章,我们会聊聊更高级的重构工具——那些能跨文件、跨模块进行大规模重构的利器。敬请期待。