Java 重构和源代码操作

Visual Studio Code 提供了许多选项来重构您的源代码,以及在编码时生成代码和修复问题的源操作。要访问它们,请在看到灯泡 💡时点击它。或者右键单击编辑器视图并选择源操作...

支持的代码操作列表

重构

Java程序重构的目标是在不影响程序行为的情况下进行系统范围的代码更改。VS Code的Java语言支持提供了许多易于访问的重构选项。

调用重构

重构命令可从编辑器的上下文菜单中获得。选择你想要重构的元素,右键点击以打开上下文菜单,然后选择重构...

调用重构

然后你将看到所有可用的重构选项。

赋值给变量

将表达式赋值给局部变量或字段。

示例

之前
Arrays.asList("apple", "lemon", "banana");
之后
List<String> fruits = Arrays.asList("apple", "lemon", "banana");

它也可以用于将构造函数中未使用的参数分配给一个新字段。

将匿名类转换为嵌套类

将匿名内部类转换为成员类。

示例

让我们将匿名类 Interface(){...} 转换为类 Clazz 的成员。

之前
public class Clazz {
  public Interface method() {
    final boolean isValid = true;
    return new Interface() {
      public boolean isValid() {
        return isValid;
      }
    };
  }
}
之后
public class Clazz {
  private final class MyInterface extends Interface {
    private final boolean isValid;

    private MyInterface(boolean isValid) {
      this.isValid = isValid;
    }

    public boolean isValid() {
      return isValid;
    }
  }

  public Interface method() {
    final boolean isValid = true;
    return new MyInterface(isValid);
  }
}

转换为匿名类创建

将lambda表达式转换为匿名类的创建。

示例

变量 runnable 被赋予了一个 lambda 表达式。让我们将其转换为匿名类的创建。

之前
public void method() {
  Runnable runnable = () -> {
    // do something
  };
}
之后
public void method() {
  Runnable runnable = new Runnable() {
    @Override
    public void run() {
      // do something
    }
  };
}

另请参阅:转换为lambda表达式

转换为增强型for循环

将简单的for循环转换为for-each风格。

示例

之前
public void order(String[] books) {
  for (int i = 0; i < books.length; i++) {
    // do something
  }
}
之后
public void order(String[] books) {
  for (String book : books) {
    // do something
  }
}

转换为lambda表达式

将匿名类创建转换为lambda表达式。

示例

让我们将匿名类 Runnable(){...} 转换为 lambda 表达式。

之前
public void method() {
  Runnable runnable = new Runnable(){
    @Override
    public void run() {
      // do something
    }
  };
}
之后
public void method() {
    Runnable runnable = () -> {
      // do something
    };
  }

另请参阅:转换为匿名类创建

转换为静态导入

将字段或方法转换为静态导入。

示例

让我们将Assert.assertEquals()调用转换为静态导入。

之前
import org.junit.Assert;
...
public void test() {
  Assert.assertEquals(expected, actual);
}
之后
import static org.junit.Assert.assertEquals;
...
public void test() {
  assertEquals(expected, actual);
}

提取为常量

从选定的表达式创建一个静态最终字段并替换字段引用,然后重写出现相同表达式的其他位置。

示例

让我们提取π的值:3.14到一个常量中。

之前
public double getArea(double r) {
  return 3.14 * r * r;
}
之后
private static final double PI = 3.14;

public double getArea(double r) {
  return PI * r * r;
}

另请参阅:Inline constant

提取到字段

声明一个新字段并用选定的表达式初始化它。原始表达式被替换为字段的使用。

示例

让我们将变量 area 提取到类 Square 的一个字段中。

之前
class Square {
  public void calculateArea() {
    int height = 1;
    int width = 2;
    int area = height * width;
  }
}
之后
class Square {
  private int area;

  public void calculateArea() {
    int height = 1;
    int width = 2;
    area = height * width;
  }
}

当选择一个变量声明时,将变量转换为字段。

提取到方法

创建一个包含当前选定的语句或表达式的新方法,并用对新方法的引用替换选定的内容。此功能对于清理冗长、杂乱或过于复杂的方法非常有用。

示例

让我们将表达式 height * width 提取到一个新方法中。

之前
public void method() {
  int height = 1;
  int width = 2;
  int area = height * width;
}
之后
public void method() {
  int height = 1;
  int width = 2;
  int area = getArea(height, width);
}

private int getArea(int height, int width) {
  return height * width;
}

另请参阅:Inline method

提取到局部变量

创建一个新变量,将其分配给当前选中的表达式,并用对新变量的引用替换选中的内容。

示例

让我们将表达式 platform.equalsIgnoreCase("MAC") 提取到一个新变量中。

之前
public void method() {
  if (platform.equalsIgnoreCase("MAC")) {
    // do something
  }
}
之后
public void method() {
  boolean isMac = platform.equalsIgnoreCase("MAC");
  if (isMac) {
    // do something
  }
}

提取后,您还可以在同一事务中执行重命名。

另请参阅:Inline local variable

内联常量

用其定义的值替换常量引用。

示例

让我们将常量 PI 替换为其定义的值:3.14

之前
private static final double PI = 3.14;

public double getArea(double r) {
  return PI * r * r;
}
之后
private static final double PI = 3.14;

public double getArea(double r) {
  return 3.14 * r * r;
}

另请参阅:Extract to constant

内联局部变量

用其初始化器替换冗余的变量使用。

示例

让我们直接将变量 isMac 替换为布尔表达式。

之前
public void method() {
  boolean isMac = platform.equalsIgnoreCase("MAC");
  if (isMac) {
    // do something
  }
}
之后
public void method() {
  if (platform.equalsIgnoreCase("MAC")) {
    // do something
  }
}

另请参阅:Extract to local variable

内联方法

用方法的主体替换对方法的调用。

示例

让我们直接将方法 getArea(int height, int width) 替换为表达式 height * width

之前
public void method() {
  int height = 1;
  int width = 2;
  int area = getArea(height, width);
}

private int getArea(int height, int width) {
  return height * width;
}
之后
public void method() {
  int height = 1;
  int width = 2;
  int area = height * width;
}

另请参阅:Extract to method

反转条件

反转条件中的布尔表达式。

示例

让我们反转if语句中的布尔表达式。

之前
public void method(int value) {
  if (value > 5 && value < 15) {
    // do something
  }
}
之后
public void method(int value) {
  if (value <= 5 || value >= 15) {
    // do something
  }
}

反转局部变量

反转本地布尔变量。

示例

让我们反转变量 valid

之前
public void method(int value) {
  boolean valid = value > 5 && value < 15;
}
之后
public void method(int value) {
  boolean notValid = value <= 5 || value >= 15;
}

移动

移动选定的元素并修正所有对元素的引用(包括在其他文件中)。可用的操作有:

  • 将类移动到另一个包
  • 将静态或实例方法移动到另一个类
  • 将内部类移动到新文件

示例

让我们将静态方法 print() 从类 Office 移动到类 Printer

之前
public class Office {
  public static void main(String[] args) {
    print();
  }

  public static void print() {
    System.out.println("This is printer");
  }

  static class Printer { }
}
之后
public class Office {
  public static void main(String[] args) {
    Printer.print();
  }

  static class Printer {
    public static void print() {
      System.out.println("This is printer");
    }
  }
}

如果静态方法在另一个类中比在其自己的类中使用得更多,则对其进行移动重构。

将一个类移动到另一个包。目前,文件资源管理器不支持移动重构。

将一个内部类移动到一个新文件中。

重命名

默认快捷键:F2

重命名所选元素并更正对该元素的所有引用(也包括在其他文件中)。

示例

让我们将类 Foo 重命名为 Bar

之前
public class Foo {
  // ...
}

public void myMethod() {
  Foo myClass = new Foo();
}
之后
public class Bar {
  // ...
}

public void myMethod() {
  Bar myClass = new Bar();
}

调用重命名重构的快捷键是 F2。当你在编辑器中对标识符调用此快捷键时,编辑器内会显示一个小框,你可以在其中更改标识符名称。当你按下 Enter 时,所有对该标识符的引用也会被更改。

文件资源管理器中也支持对文件夹和文件进行重命名重构。在请求更改后,将提供受影响文件的预览,您可以决定如何应用这些更改。

从资源管理器重命名

将解析类型更改为var类型

使用 var 来声明局部变量。

示例

之前
String s = "";
之后
var s = "";

另请参阅:Change var type to resolved type


将变量类型更改为解析类型

使用解析的类型来声明局部变量。

示例

之前
var s = "";
之后
String s = "";

另请参阅:Change resolved type to var type

源操作

源操作可用于生成常见的代码结构和重复元素。其中一些是快速修复,帮助您即时修复代码问题。

生成构造函数

为类添加一个构造函数。

生成委托方法

生成委托方法

重写/实现方法

使用此源操作,所有候选者都会以清单的形式呈现给您。然后您可以决定要覆盖或实现的内容。

组织导入

您可以使用此源操作来清理您的导入。它还可以处理模糊的导入,在这种情况下,将显示一个下拉列表供您选择正确的导入。未解析类型的代码行也会显示给您,以帮助您做出决定。

生成getters和setters

您可以批量生成所有新成员变量的getter和setter方法。如果类中有多个字段,源操作将提示一个快速选择,供您选择目标字段以生成访问器方法。

生成 hashCode()equals()

hashCode()equals() 可以使用默认实现生成。所有非静态成员变量都会被列出,您可以使用复选框自定义生成的代码。

有两种选项供您自定义生成的代码:

  • 如果您使用 Java 7+,可以将 java.codeGeneration.hashCodeEquals.useJava7Objects 设置为 true 以生成调用 Objects.hashObjects.equals 的更短代码。
  • 你也可以将java.codeGeneration.hashCodeEquals.useInstanceof设置为true,以使用instanceOf操作符来检查对象类型,而不是调用Object.getClass()

生成 toString()

有一个新的源操作可以生成toString()方法。可以通过所有成员变量的复选框进行自定义。

尽可能将修饰符更改为final

final修饰符添加到当前源文件中的所有变量和参数。

示例

之前
public class Clazz {
  public void method(int value) {
    boolean notValid = value > 5;
    if (notValid) {
      // do something
    }
  }
}
之后
public class Clazz {
  public void method(final int value) {
    final boolean notValid = value > 5;
    if (notValid) {
      // do something
    }
  }
}

修复不可访问的引用

此快速修复帮助您修复不可访问的引用。

创建不存在的包

当您的包名称与文件夹名称不匹配时,您可以选择在源代码中更改包名称,或在文件系统中移动文件夹(即使目标文件夹尚不存在)。

支持的其他代码操作

VS Code 支持的代码操作列表不断增长,上面仅列出了最受欢迎的一些。其他值得注意的支持操作包括(但不限于):

  • 创建未解析的类型
  • 移除final修饰符
  • 移除不必要的类型转换
  • 移除冗余接口
  • 在switch语句中添加缺失的case标签
  • 跳转到break/continue的定义
  • 正确访问静态元素