🚀 在 VS Code 中

Java 重構與原始碼動作

Visual Studio Code 提供許多選項來重構您的原始碼,以及原始碼動作,以便在您撰寫程式碼時產生程式碼和修正問題。若要存取這些選項,請按一下您看到的 燈泡 💡。或在編輯器檢視中按一下滑鼠右鍵,然後選擇 原始碼動作...

支援的程式碼動作清單

重構

Java 程式重構的目標是在不影響程式行為的情況下,進行系統範圍的程式碼變更。適用於 VS Code 的 Java 語言支援提供許多容易存取的重構選項。

叫用重構

重構命令可從編輯器的內容功能表取得。選取您要重構的元素,按一下滑鼠右鍵以開啟內容功能表,然後選擇 重構...

Invoke Refactoring

然後您將看到所有可用的重構選項。

指派給變數

將運算式指派給區域變數或欄位。

範例

之前
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 時,也會變更對該識別項的所有參考。

檔案總管也支援資料夾和檔案的重新命名重構。要求變更後,將提供受影響檔案的預覽,您可以決定如何套用這些變更。

Rename from Explorer

將已解析類型變更為 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.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 的定義
  • 更正對靜態元素的存取