Java のリファクタリングとソース アクション
Visual Studio Code には、ソース コードをリファクタリングするための多くのオプションと、コーディング中にコードを生成したり問題を修正したりするためのソース アクションが用意されています。これらにアクセスするには、電球
💡 が表示されたらいつでもクリックします。または、エディター ビューを右クリックして [ソース アクション...] を選択します。
サポートされているコード アクションの一覧
- リファクタリング
- 変数に割り当てる
- 匿名クラスをネストしたクラスに変換する
- 匿名クラスの作成に変換する
- 拡張 for ループに変換する
- ラムダ式に変換する
- 静的インポートに変換する
- 抽出リファクタリング
- インライン リファクタリング
- ブール値の反転
- 移動
- 名前の変更
- 型の変更
- ソース アクション
- サポートされているその他のコード アクション
リファクタリング
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);
}
}
匿名クラスの作成に変換する
ラムダ式を匿名クラスの作成に変換します。
例
変数 runnable
にはラムダ式が割り当てられています。これを匿名クラスの作成に変換してみましょう。
以前
public void method() {
Runnable runnable = () -> {
// do something
};
}
以後
public void method() {
Runnable runnable = new Runnable() {
@Override
public void run() {
// do something
}
};
}
関連項目: ラムダ式に変換する
拡張 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
}
}
ラムダ式に変換する
匿名クラスの作成をラムダ式に変換します。
例
匿名クラス 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);
}
定数に抽出
選択された式から静的な 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()
は、既定の実装で生成できます。静的でないすべてのメンバー変数がリストされ、チェックリストを使用して生成されるコードをカスタマイズできます。
生成されるコードをカスタマイズするためのオプションは 2 つあります。
- Java 7+ を使用している場合、
java.codeGeneration.hashCodeEquals.useJava7Objects
をtrue
に設定すると、Objects.hash
とObjects.equals
を呼び出す短いコードを生成できます。 - また、
java.codeGeneration.hashCodeEquals.useInstanceof
をtrue
に設定すると、Object.getClass()
を呼び出す代わりにinstanceOf
演算子を使用してオブジェクトの型をチェックできます。
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 で定義にジャンプする
- 静的要素へのアクセスを修正する