Java 重构和代码操作
Visual Studio Code 提供了许多重构源代码的选项,以及用于在编码时生成代码和修复问题的代码操作。要访问它们,请点击您看到的任何灯泡💡。或者右键单击编辑器视图并选择代码操作...。
支持的代码操作列表
- 重构
- 分配给变量
- 将匿名内部类转换为嵌套类
- 转换为匿名类创建
- 转换为增强 for 循环
- 转换为 lambda 表达式
- 转换为静态导入
- 提取重构
- 内联重构
- 反转布尔值
- 移动
- 重命名
- 类型更改
- 代码操作
- 支持的其他代码操作
重构
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);
}
提取到常量
从选定的表达式创建一个静态 final 字段并替换为字段引用,然后重写同一表达式出现的其他位置。
示例
让我们将 π 的值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;
}
另请参阅:内联常量
提取到字段
声明一个新字段并用选定的表达式初始化它。原始表达式将被字段的使用替换。
示例
让我们将变量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;
}
另请参阅:内联方法
提取到局部变量
创建一个新变量,用当前选定的表达式对其进行赋值,并将选定内容替换为对新变量的引用。
示例
让我们将表达式platform.equalsIgnoreCase("MAC")提取到一个新变量中。
之前
public void method() {
if (platform.equalsIgnoreCase("MAC")) {
// do something
}
}
之后
public void method() {
boolean isMac = platform.equalsIgnoreCase("MAC");
if (isMac) {
// do something
}
}
提取后,您还可以在同一事务中执行重命名。
另请参阅:内联局部变量
内联常量
用其定义值替换常量引用。
示例
让我们将常量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;
}
另请参阅:提取到常量
内联局部变量
用其初始化程序替换冗余的变量使用。
示例
让我们将变量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)直接替换为表达式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;
}
另请参阅:提取到方法
反转条件
反转条件中的布尔表达式。
示例
让我们反转 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;
}
移动
移动选定的元素并更正所有对这些元素的引用(包括在其他文件中)。可用的操作包括
- 将类移动到另一个包
- 将静态或实例方法移动到另一个类
- 将内部类移动到新文件
示例
让我们将类Office中的静态方法print()移动到类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 = "";
另请参阅:将 var 类型更改为已解析类型
将 var 类型更改为已解析类型
使用已解析类型声明局部变量。
示例
之前
var s = "";
之后
String s = "";
另请参阅:将已解析类型更改为 var 类型
代码操作
代码操作可用于生成常见的代码结构和重复元素。其中一些是快速修复,可帮助您即时修复代码问题。
生成构造函数
为类添加构造函数。
生成委托方法
生成委托方法
覆盖/实现方法
使用此代码操作,所有候选对象都会以清单形式呈现给您。然后,您可以决定要覆盖或实现的内容。
整理导入
您可以使用此代码操作来清理您的导入。它还可以处理歧义导入,在这种情况下,将显示一个下拉列表供您选择正确的选项。还会显示带有未解析类型的代码行,以帮助您做出决定。
生成 getter 和 setter
您可以批量生成所有新成员变量的 getter 和 setter。如果类有多个字段,代码操作将提示一个快速选择,供您选择要用于生成访问器方法的字段。
生成hashCode()和equals()
可以使用默认实现生成hashCode()和equals()。列出了所有非静态成员变量,您可以使用清单来自定义生成的代码。
有两种选项可供您自定义生成的代码
- 如果您使用 Java 7 或更高版本,可以将
java.codeGeneration.hashCodeEquals.useJava7Objects设置为true,以生成更短的代码,该代码调用Objects.hash和Objects.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 的定义
- 更正对静态元素的访问