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;
}
移動
移動所選元素並更正對這些元素的所有引用(在其他檔案中也是如此)。可用的操作有
- 將類移動到另一個包
- 將靜態或例項方法移動到另一個類
- 將內部類移動到新檔案
示例
讓我們將靜態方法 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 = "";
另請參閱:將 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 上跳轉到定義
- 更正對靜態成員的訪問