Java 重构与源动作

Visual Studio Code 提供了多种重构源代码和源代码作(Source Actions)选项,用于生成代码并在编码过程中解决问题。要访问这些内容,请点击灯泡💡 只要你看到它。或者右键点击编辑器视图,选择“源作......”。

支持的代码动作列表

重构

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

调用重构

重构命令可通过编辑器的上下文菜单调用。选择你想重构的元素,右键点击打开右键菜单,然后选择重构......

调用重构

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

赋值到 变量

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

示例

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

它还可用于为构造器中未使用的参数分配到新字段。

将匿名类转换为嵌套类

将一个匿名的内类转换为成员类。

示例

我们转换匿名类Interface(){...}与该阶级成员咔嚓.

之前
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 表达式转换为匿名类创建。

示例

变量可运行被赋予一个λ表达式。我们把它转换成一个匿名的类创建。

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

另见:转换为λ表达式

转换为增强型 for 循环

简单映射对于环路到对每个风格。

示例

之前
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
  }
}

转换为λ表达式

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

示例

我们转换匿名类Runnable(){...}到λ表达式。

之前
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;
}

另见:内联常数

从抽取到场

声明一个新字段,并用所选表达式初始化。原表达式被场的使用所取代。

示例

我们提取变量区域到该类域方形.

之前
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;
  }
}

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

从提取到方法

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

示例

我们提取表达式高度 * 宽度换成一种新的方法。

之前
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;
}

另见:内联方法

提取到局部变量

为当前选择的表达式创建一个新变量,并用新变量的引用替换该选区。

示例

我们提取表达式platform.equalsIgnoreCase(“MAC”)变为一个新变量。

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

提取完成后,你也可以在同一交易中进行重命名。

另见:内联局部变量

直列常数

用定义值替换常数引用。

示例

我们替换常数私家侦探到其定义值: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;
}

另见:提取至常数

内联局部变量

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

示例

我们替换变量isMac直接映射到布尔表达式。

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

另见:提取到局部变量

内联方法

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

示例

我们替换方法getArea(int height, int 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;
}

另见:从萃取到方法

倒挂条件

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

示例

我们来反演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
  }
}

反转局部变量

反转局部布尔变量。

示例

我们反演变量有效.

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

让开

移动所选元素并纠正所有对该元素的引用(其他文件中的引用)。可用的行动包括:

  • 把班级转到另一个套餐
  • 将静态方法或实例方法迁移到另一个类
  • 将内类迁移到新文件

示例

让我们来移动静态方法print()来自课堂办公室上课打印机.

之前
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

重命名所选元素并纠正所有对该元素的引用(其他文件中的引用)。

示例

我们给这个类别重新命名吧酒吧

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

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

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

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

文件资源管理器也支持重命名重构,适用于文件夹和文件。请求更改后,会预览受影响文件,您可以决定如何应用这些更改。

从Explorer更名

将已解析类型改为var类型

用途VAR以声明局部变量。

示例

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

另见:将变量类型更改为解析类型


将var类型改为解析类型

使用解析类型声明本地变量。

示例

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

另见:将已解析类型更改为变量类型

源头动作

源动作可以用来生成常见的代码结构和重复出现的元素。其中一些是快速修复,帮助你实时修复代码问题。

生成构造子

为该类添加一个构造函数。

生成代理方法

生成代理方法

覆盖/实现方法

通过这个源行动,所有候选人都会被呈现给你一份清单。然后你可以决定覆盖或实现哪些。

组织导入

你可以用这个源作来清理导入。它也可以处理歧义导入,在这种情况下,会显示一个下拉列表,供你选择合适的导入。未解决类型的代码行也会显示给你,帮助你做出决定。

生成抓取者和二传者

你可以批量生成所有新成员变量的获取器和设置器。如果类有多个字段,源作会提示快速选择,让你选择用于生成访问器方法的目标字段。

生成hashCode()以及等值()

hashCode()以及等值()可以用默认实现生成。所有非静态成员变量都列出了,你可以用检查列表自定义生成代码。

你可以选择两种方式自定义生成代码:

  • 如果你用的是Java 7+,你可以设置java.codeGeneration.hashCodeEquals.useJava7Objects确实如此生成更短的调用代码Objects.hash以及Objects.equals.
  • 你也可以设置java.codeGeneration.hashCodeEquals.useInstanceof确实如此使用实例作符来检查对象类型,而不是调用Object.getClass().

生成toString()

有一个新的源动作来生成toString()方法。通过所有成员变量的检查列表,可以进行自定义。

尽可能将修饰符改为结尾

补充决赛修改器对当前源文件中的所有变量和参数。

示例

之前
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 支持的代码动作列表持续增长,仅列出上述最受欢迎的动作。其他值得注意的支持动作包括(但不限于):

  • 创建未解决类型
  • 移除决赛修饰语
  • 去除不必要的石膏
  • 移除冗余接口
  • 在切换语句中添加缺失的格标签
  • 跳转到休息/继续时的定义
  • 正确访问静态元素