1. 概述

代码整洁不是一件容易的事,幸运的是,现代 IDE 非常智能,可以帮助我们完成这项任务。本文将深入介绍 IntelliJ IDEA 提供的多种重构功能,涵盖从变量重命名到方法签名修改等常见操作。

这些功能不仅提升了代码可读性,还能帮助我们更高效地进行代码维护。如果你经常使用 IntelliJ,掌握这些重构技巧绝对能让你事半功倍。


2. 重命名(Renaming)

2.1 基础重命名

重命名是重构中最基础也最常用的功能之一。✅IntelliJ 支持对类、方法、变量、参数甚至包进行智能重命名,并自动更新所有引用。

操作步骤如下:

  • 右键点击目标元素
  • 选择 Refactor > Rename
  • 输入新名称
  • 回车确认

或者直接使用快捷键:Shift + F6

例如,我们有一个类:

public class SimpleClass {
    public static void main(String[] args) {
        new SimpleClass().someAdditionMethod(1, 2);
    }

    public int someAdditionMethod(int a, int b) {
        return a + b;
    }
}

someAdditionMethod 重命名为 add 后,IntelliJ 会自动更新所有调用点:

public class SimpleClass {
    public static void main(String[] args) {
        new SimpleClass().add(1, 2);
    }

    public int add(int a, int b) {
        return a + b;
    }
}

2.2 高级重命名

除了基本的代码引用,IntelliJ 还支持在注释和字符串中搜索并重命名,甚至可以处理继承结构中的参数名。

高级选项包括:

  • ✅Search in comments and strings:在注释和字符串中查找匹配
  • ✅Search for text occurrences:在非代码文件中查找匹配
  • ✅Rename parameters in hierarchy:在方法继承结构中同步参数名

比如我们有如下方法:

/**
 * Adds a and b
 * @param a the first number
 * @param b the second number
 */
public int add(int a, int b) {...}

如果我们重命名参数 afirstNumber,并启用“Search in comments and strings”,IntelliJ 会自动更新注释:

/**
 * Adds firstNumber and b
 * @param firstNumber the first number
 * @param b the second number
 */
public int add(int firstNumber, int b) {...}

⚠️注意:IntelliJ 默认只搜索当前元素作用域内的内容,因此外部注释不会被影响。


3. 提取(Extracting)

提取是指将代码片段封装成变量、方法或类,是重构中非常实用的功能。

3.1 提取变量

操作步骤如下:

  • 选中表达式
  • 右键选择 Refactor > Extract > Variable/Parameter/Field/Constant
  • 输入变量名
  • 回车

快捷键分别是:

  • Ctrl + Alt + V:提取为局部变量
  • Ctrl + Alt + P:提取为参数
  • Ctrl + Alt + F:提取为字段
  • Ctrl + Alt + C:提取为常量

例如:

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    return LocalDate.now().isAfter(startingDate) && LocalDate.now().isBefore(endingDate);
}

选中 LocalDate.now() 并提取为变量:

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    LocalDate now = LocalDate.now();
    return now.isAfter(startingDate) && now.isBefore(endingDate);
}

勾选 Replace all occurrences 可一次性替换所有引用。

3.2 提取方法

操作步骤如下:

  • 选中代码块
  • 右键选择 Refactor > Extract > Method
  • 输入方法名、可见性、参数
  • 回车

快捷键:Ctrl + Alt + M

例如:

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    LocalDate now = LocalDate.now();
    return now.isAfter(startingDate) && now.isBefore(endingDate);
}

选中 now.isAfter(startingDate) && now.isBefore(endingDate) 并提取为方法:

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    LocalDate now = LocalDate.now();
    return isDateBetween(now, startingDate, endingDate);
}

private static boolean isDateBetween(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
    return date.isBefore(endingDate) && date.isAfter(startingDate);
}

默认生成的为私有方法,可在弹窗中修改可见性。

3.3 提取类

将方法封装为工具类也很方便。操作如下:

  • 右键类名
  • 选择 Refactor > Extract > Delegate
  • 输入类名、包名、要委托的方法
  • 回车

例如将 isNowBetweenisDateBetween 提取为 DateUtils 类:

public class DateUtils {
    public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
        LocalDate now = LocalDate.now();
        return isDateBetween(now, startingDate, endingDate);
    }

    public static boolean isDateBetween(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
        return date.isBefore(endingDate) && date.isAfter(startingDate);
    }
}

默认方法可见性为 public,确保外部调用不报错。


4. 内联(Inlining)

内联是提取的反操作,即将变量或方法调用替换为原始表达式或方法体。

操作步骤如下:

  • 右键点击变量或方法
  • 选择 Refactor > Inline
  • 选择替换方式

快捷键:Ctrl + Alt + N

例如,我们想将 now 变量内联:

public static boolean isNowBetween(LocalDate startingDate, LocalDate endingDate) {
    return isDateBetween(LocalDate.now(), startingDate, endingDate);
}

对于方法,可以选择:

  • ✅替换所有调用并删除方法
  • ✅替换所有调用但保留方法
  • ✅仅替换当前调用

5. 移动(Moving)

将方法从一个类移动到另一个类,IntelliJ 会自动处理引用和可见性。

操作步骤如下:

  • 选中方法
  • 右键选择 Refactor > Move
  • 选择目标类和可见性
  • 回车

快捷键:F6

例如将 isDateOutsideSimpleClass 移动到 DateUtils

public static boolean isDateOutside(LocalDate date, LocalDate startingDate, LocalDate endingDate) {
    return !isDateBetween(date, startingDate, endingDate);
}

如果是实例方法,IntelliJ 会查找字段引用的类并建议移动到其中,否则建议设为 static


6. 修改方法签名(Change Method Signature)

修改方法名、参数、返回值类型等。

操作步骤如下:

  • 选中方法
  • 右键选择 Refactor > Change Signature
  • 修改签名内容
  • 回车

快捷键:Ctrl + F6

例如给 isDateBetween 添加一个 boolean inclusive 参数:

public static boolean isDateBetween(LocalDate date, LocalDate startingDate,
   LocalDate endingDate, boolean inclusive) {
    return date.isBefore(endingDate) && date.isAfter(startingDate);
}

可勾选 Delegate via overloading method 创建重载方法,避免破坏现有调用。


7. 上提与下放(Pull Up & Push Down)

7.1 上提成员(Pull Up)

将子类成员上提到父类。

操作步骤如下:

  • 选中成员
  • 右键选择 Refactor > Pull Members Up…
  • 点击 Refactor

例如将 Derived 类中的 doubleValue() 上提到 Base 类:

public class Base {
    protected int doubleValue(int number) {
        return number + number;
    }
}

方法可见性自动从 private 改为 protected

7.2 下放成员(Push Down)

将父类成员下放到子类。

操作步骤如下:

  • 选中成员
  • 右键选择 Refactor > Push Members Down…
  • 点击 Refactor

例如将 Base 类的 doubleValue() 下放到 Derived 类:

public class Derived extends Base {
    protected int doubleValue(int number) {
        return number + number;
    }
}

如果存在多个子类,IntelliJ 会自动下放到所有子类。


8. 总结

本文详细介绍了 IntelliJ IDEA 提供的多种重构功能,包括:

  • ✅重命名:支持高级选项,如注释、字符串、继承结构
  • ✅提取:变量、方法、类
  • ✅内联:替换变量或方法调用为原始内容
  • ✅移动:将方法移动到其他类
  • ✅修改方法签名:调整方法名、参数、返回值
  • ✅上提与下放:在继承结构中移动成员

这些功能极大地提升了代码质量和维护效率。如果你还没用过这些重构技巧,建议尽快上手实践,它们绝对值得你花时间掌握。

如需了解更多 IntelliJ 功能,可参考其官方文档


原始标题:An Introduction to Refactoring with IntelliJ IDEA | Baeldung