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 型に変更
ソースアクション
ソースアクションは、一般的なコード構造や繰り返し出現する要素を生成するために使用できます。その中には、コーディング中にコードの問題を即座に修正するのに役立つクイックフィックスも含まれます。
コンストラクターを生成
クラスのコンストラクターを追加します。
デリゲートメソッドを生成
デリゲートメソッドを生成
メソッドをオーバーライド/実装
このソースアクションを使用すると、すべての候補がチェックリスト形式で提示されます。その後、何をオーバーライドまたは実装するかを決定できます。
インポートを整理
このソースアクションを使用して、インポートを整理できます。曖昧なインポートも処理でき、その場合は、正しいものを選択するためのドロップダウンリストが表示されます。未解決の型があるコード行も、決定を助けるために提示されます。
ゲッターとセッターを生成
すべての新しいメンバー変数に対してゲッターとセッターを一括生成できます。クラスに複数のフィールドがある場合、ソースアクションはアクセサーメソッドの生成に使用するターゲットフィールドを選択するためのクイックピックを促します。
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 で定義にジャンプ
- 静的要素へのアクセスを修正