Android Studio最速入門~効率的にコーディングするための使い方

第37回リファクタリング・カタログ

はじめに

今回は、数多くあるAndroid Studioのリファクタリングメニューについて、1つずつ紹介していきます。表題のカッコは対応するコマンド名です。それぞれの内容の詳細については、IntelliJ IDEA Web Helpが詳しいです。

リネーム(Rename, Rename File)

実はリネームは2種類あります。"Rename..."は前回説明したとおりですが、もう一方の"Rename File..."は今回初めて紹介します。名称からわかるようにファイル名のリネームだけを行います。

図1 "Rename File..."のときの「Rename」ダイアログ
図1

Javaのファイルに対して"Rename File..."を実行すると、ファイル名しか変わりません。クラス名はそのままです。"Rename..."でもファイル名のリネームはできるので、正直なんのためにあるかわかりません。

使い方

  1. エディタや「Projectツールウィンドウ」上で、リネームしたいファイルやシンボルを選択
  2. "Rename..."を実行

シグネチャの変更(Change Signature)

メソッドの宣言部や呼び出し部分で実行すれば、メソッドシグネチャの変更。クラスの宣言部や型指定部分で実行すればクラスシグネチャの変更になります。

メソッドシグネチャでは、メソッドの引数だけではなく、可視性、戻り値、送出する例外を変更することができます。

図2 ⁠Change Class Signature」ダイアログ(クラスの時)
図2
図3 ⁠Change Signature」ダイアログ(メソッドの時)
図3

使い方

  1. エディタ上で、シグネチャを変更したいメソッドやクラスにカーソルを置く
  2. "Change Signature..."を実行

型のマイグレーション(Type Migration)

インスタンス変数や型パラメタの型を他の型に変換します。たとえば intStringに、といった具合です。

図4 ⁠Type Migration」ダイアログ
図4

使い方

  1. エディタ上で型を表している部分にカーソルを置く
  2. "Type Migration..."を実行

スタティック化(Make Static)

インスタンスメソッドや内部クラスをスタティックに変換します。

図5 ⁠Make Method Static」ダイアログ
図5

使い方

  1. 「Structureツールウィンドウ」やエディタ上で、スタティック化したいメソッドやクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Make Static..."を実行

インスタンスメソッドに変換(Convert To Instance Method)

スタティックメソッドをインスタンスメソッドに変換します。先ほど紹介した「スタティック化」の逆を行います。

図6 ⁠Convert To Instance Method」ダイアログ
図6

使い方

  1. エディタ上で変換したいメソッドにカーソルを置く
  2. "Convert To Instance Method..."を実行

移動(Move)

主に「Projectツールウィンドウ」上でのファイルの移動に用いますが、メソッドや内部クラスも対象にできます。

図7 ⁠Move Members」ダイアログ
図7

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタ上で対象を選ぶ(エディタの場合、カーソルを置く)
  2. "Move..."を実行
    • 「Projectツールウィンドウ」の場合は、ドラッグ&ドロップで移動(Move)になります。さらに「Show Members」オプションを有効にすると、メンバの移動もドラッグ&ドロップで可能になります。
    • にもかかわらず、⁠Structureツールウィンドウ」ではドラッグ&ドロップ操作はできません。

コピー(Copy, Clone)

主に「Projectツールウィンドウ」上でのファイルのコピーに用います。移動ではメソッドやフィールドなどのメンバも対象にできましたが、コピーはクラスやインターフェイスのみが対象です。

"Clone..."は「Rafactor」メニューに存在しないのですが、"Find Action..."や「Preferences / Keymap」でその存在を確認することができます。"Copy..."との違いは「コピーを(コピー元と)同じディレクトリに作成するかどうか」の違いしかありません。実にしょうも無い違いなので "Clone..." は忘れていても困ることはありません。

図8 ⁠Copy」ダイアログ(上)「Clone」ダイアログ(下)
図8

使い方

  1. 「Projectツールウィンドウ」やエディタ上で対象を選ぶ(エディタの場合、カーソルを置く)
  2. "Copy..." または "Clone..." を実行
    • 「Projectツールウィンドウ」の場合は、ドラッグ&ドロップで移動(Move⁠⁠、Ctrlキーを押しながらドラッグ&ドロップでコピー(Copy)になります。

安全な削除(Safe Delete)

主に「Projectツールウィンドウ」上でのファイルの削除に用います。移動Move...と同じく、クラスやインターフェイス以外にメソッドやインスタンス変数なども削除対象になります。

図9 ⁠Safe Delete」ダイアログ
図9

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタ上で対象を選ぶ(エディタの場合、カーソルを置く)
  2. "Safe Delete..." を実行

抽出(Extract)

JavaやXMLのコード片から変数やメソッド、外部定義を抜き出す抽出系リファクタリングです。このリファクタリングはちょっとユニークで、一部の抽出系リファクタリングでは、カーソル位置を基準に抽出可能なコード片を候補を示します。

図10 抽出可能な範囲が複数ある場合はそれが候補にでる(クリックすると動きがわかります)

また抽出系リファクタリングは、リネームとは毛色の異なるIn-placeモードで実行していくのも特徴です。

ローカル変数の抽出(Variable)

選択した式をローカル変数にします。実を言うと第11回で紹介した「Introduce local variable」と仕組みは同じなのです。

図11 ローカル変数の抽出例(クリックすると動きがわかります)

使い方

  1. エディタ上でローカル変数に置き換えたい式にカーソルを置く
  2. "Variable..."を実行
    • カーソル位置から置換可能な式の候補が複数ある場合は、どれを置換するか指定する
    • 置き換える式が複数箇所で見つかった場合、すべて置換するかどうかを指定する

定数(クラス変数)の抽出(Constant)

選択した式をクラス変数にします。また、このリファクタリングはインテンションでも提供されており、文字列リテラルの上で"Introduce Constant"を実行しても同様のことができます。

図12 定数の抽出例(クリックすると動きがわかります)

使い方

  1. エディタ上でクラス変数に置き換えたい式または宣言にカーソルを置く
  2. "Constant..."を実行

フィールド(インスタンス変数)の抽出(Field)

選択した式をインスタンス変数にします。このとき、インスタンス変数を初期化する場所を指定できます。

図13 フィールドの抽出例(クリックすると動きがわかります)

使い方

  1. エディタ上でインスタンス変数に置き換えたい式または宣言にカーソルを置く
  2. "Field..."を実行

引数の抽出(Parameter)

メソッド内の式を、そのメソッドの引数にします。この際、既存のメソッドに新しい引数を追加するか、既存のメソッドをオーバーロードした新しいメソッドを作成するか選べます。

図14 引数の抽出例(クリックすると動きがわかります)

使い方

  1. エディタ上で引数に置き換えたい式にカーソルを置く
  2. "Parameter..."を実行

パラメタオブジェクトの抽出(Parameter Object)

メソッドの引数をまとめたラッパークラスを作成するか、既存のクラスに置き換えます。

使い方

  1. 「Structureツールウィンドウ」またはエディタで、パラメタオブジェクトを適用したいメソッドを選ぶ(エディタの場合、カーソルを置く)
  2. "Parameter Object..."を実行(⁠⁠Introduce Parameter Object」ダイアログに諸設定を行う)
図15 ⁠Introduce Parameter Object」ダイアログ
図15

メソッドの抽出(Method)

選択した範囲(コードブロック)をメソッドとして抽出します。

使い方

  1. エディタ上で、メソッドにしたいコードブロックを選択
  2. "Method..."を実行(⁠⁠Extract Method」ダイアログに諸設定を行う)
図16 ⁠Extract Method」ダイアログ
図16

メソッドオブジェクトの抽出(Method Object)

選択した範囲(コードブロック)をメソッドではなく、その処理だけを行う専用のクラス(メソッドオブジェクト)として抽出します。実行メソッド名は常に invoke() になるようです。

使い方

  1. エディタ上で、メソッドオブジェクトにしたいコードブロックを選択
  2. "Method Object..."を実行(⁠⁠Extract Method Object」ダイアログに諸設定を行う)
図17 ⁠Extract Method Object」ダイアログ
図17

クラスの抽出(Delegate)

既存のクラスの一部(フィールドやメソッドなど)を新しいクラスに抽出します。元のクラスは、新しいクラスに機能を委譲(デリゲート)します。

コマンド名は"Delegate..."(委譲)ですが、やってることはクラスの抽出です。意味的にはどちらも同じなのですが、ダイアログは「Extract Class」となっていたり妙な混乱を誘います。

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタで対象のクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Delegate..."を実行(⁠⁠Extract Class」ダイアログに諸設定を行う)
図18 ⁠Extract Class」ダイアログ
図18

インターフェイスの抽出(Interface)

エディタや「Projectツールウィンドウ」などで対象クラスを選択して、このリファクタリングを実行すると、インターフェイスに抽出可能な要素がリストアップされたダイアログが表示されます。

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタで対象のクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Interface..."を実行(⁠⁠Extract Interface」ダイアログに諸設定を行う)
図19 ⁠Extract Interface」ダイアログ
図19

スーパークラスの抽出(Superclass)

「インターフェイスの抽出」のスーパークラス版です。

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタで対象のクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Superclass..."を実行(⁠⁠Extract Superclass」ダイアログに諸設定を行う)
図20 ⁠Extract Superclass」ダイアログ
図20

スタイルの抽出(Style)

Android固有のリファクタリングです。レイアウトリソースからスタイルを抽出します。抽出したスタイルは style.xml に定義され、抽出元は style属性に置き換えられます。

使い方

  1. エディタ上で、スタイルを抽出したいXMLエレメントにカーソルを置く
  2. "Style..."を実行(⁠⁠Extract Android Style」ダイアログに諸設定を行う)
図21 ⁠Extract Android Style」ダイアログ
図21

レイアウトの抽出(Layout)

Android固有のリファクタリングです。レイアウトリソースを分離して別ファイルに抽出します。抽出した後は <include layout="..."> に置き換えられます。

使い方

  1. エディタ上で、レイアウトを分離したいXMLエレメントにカーソルを置く(もしくは範囲を選択する)
  2. "Layout..."を実行(⁠⁠Extract Android Layout」ダイアログに諸設定を行う)
図22 ⁠Extract Android Layout」ダイアログ
図22

インライン化(Inline)

変数/メソッド(コンストラクタ含む⁠⁠/定数/スーパークラスをインラインに展開します。抽出系リファクタリングの逆を行います。

使い方

  1. エディタ上でインライン化したいシンボルにカーソルを置く
  2. "Inline..."を実行(インライン化可能な箇所が複数ある場合、すべてを変更するかどうかを問い合わせてきます)
図23 ⁠Inline Variable」ダイアログ(ローカル変数のインライン化)
図23
図24 ⁠Inline Method」ダイアログ(メソッドのインライン化)
図24

重複したコードの置換(Find and Replace Code Deplicates)

選択したメソッドに類似したコードを検索し、該当箇所をそのメソッドの呼び出しに置き換えます。

使い方

  1. エディタ上で対象にしたいメソッドにカーソルを置く
  2. "Find and Replace Code Deplicates..."を実行(⁠⁠Specify Replace Code Duplicates Scope」ダイアログに重複コードを探す範囲を指定します)
図25 ⁠Specify Replace Code Duplicates Scope」ダイアログ(クリックすると動きがわかります)

真偽の反転(Invert Boolean)

メソッドや変数のBoolean値を反転させます。

使い方

  1. エディタ上で対象にしたいメソッドや変数にカーソルを置く
  2. "Invert Boolean..."を実行
図26 ⁠Invert Boolean」ダイアログ
図26

メンバのプルアップ(Pull Members Up)

クラスのメンバ(クラス変数、インスタンス変数、メソッドなど)をスーパークラスやインターフェイスに移動します。

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタで対象のクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Pull Members Up..."を実行
図27 ⁠Pull Members Up」ダイアログ
図27

メンバのプッシュダウン(Push Members Down)

プルアップの逆で、クラスのメンバをサブクラスや下位のインターフェイスに移動します。

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタで対象のクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Push Members Down..."を実行
図28 ⁠Push Members Down」ダイアログ
図28

可能ならばインターフェイスを使用する(Use Interface Where Possible)

指定したクラスの参照箇所をインターフェイスに置き換え可能ならばインターフェイスに置き換えます(スーパークラスにも置き換え可能⁠⁠。

使い方

  1. エディタ上で、インターフェイスやスーパークラスに置換したいクラスにカーソルを置く
  2. "Use Interface Where Possible..."を実行
図29 ⁠Use Interface Where Possible」ダイアログ
図29

継承をデリゲートに置き換える(Replace Inheritance with Delegation)

親クラスの継承関係を外して、その部分を委譲(デリゲート)に置き換えます。

使い方

  1. 「Projectツールウィンドウ」「Structureツールウィンドウ⁠⁠、エディタで対象のクラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Replace Inheritance with Delegation..."を実行
図30 ⁠Replace Inheritance with Delegation」ダイアログ
図30

仲介人の削除(Remove Middleman)

デリゲートしている処理を、直接デリゲート先に受け渡すような処理に置き換えます。文章だとわかりづらいですが、リスト1リスト2に変えるようなリファクタリングを行います。

リスト1 Remove Middleman前のコード
// 呼び出し側
String str = new Foo().getBarValue();

// Foo.java
public String getBarValue() {
  return bar.getString();
}
リスト2 Remove Middleman前のコード
// 呼び出し側
String str = new Foo().getBar().getString();

// Foo.java
public String getBar() {
  return bar;
}

シチュエーションが限定的過ぎて、正直いつ使うのかわからないリファクタリングです。

使い方

  1. 「Structureツールウィンドウ」やエディタ上で、デリゲート対象のインスタンス変数を選ぶ(エディタの場合、カーソルを置く)
  2. "Remove Middleman..."を実行
図31 ⁠Remove Middleman」ダイアログ(クリックすると動きがわかります)

メソッドの戻り値をラップする(Wrap Method Return Value)

指定したメソッドの戻り値を新しいラッパークラスに置き換えるか、既存のクラスの置き換えます。

使い方

  1. エディタで対象のメソッドにカーソルを置く
  2. "Wrap Method Return Value..."を実行
図32 ⁠Wrap Return Value」ダイアログ
図32

匿名クラスを内部クラスに変換(Convert Anonymous to Inner)

表題の通りです。

使い方

  1. 「Structureツールウィンドウ」やエディタで匿名クラスを選ぶ(エディタの場合、カーソルを置く)
  2. "Convert Anonymous to Inner..."を実行
図33 ⁠Convert Anonymous to Inner」ダイアログ
図33

フィールドのカプセル化(Encapsulate Fields)

インスタンス変数に直接アクセスせず、getter/setterを介して行うようにします。

使い方

  1. 以下のいずれかの方法で対象を選ぶ
    • エディタの場合、フィールドそのものか、そのフィールドを含むクラスにカーソルを置く
    • 「Projectツールウィンドウ」の場合、クラスを選ぶ
    • 「Structureツールウィンドウ」の場合、フィールドを1つまたは複数選ぶ
  2. "Encapsulate Fields..."を実行
図34 ⁠Encapsulate Fields」ダイアログ
図34

一時的な変数をクエリに置き換える(Replace Temp with Query)

この一見意味のわからないリファクタリングは、メソッド内の変数の初期化部分を走査して、他の参照やメソッドを抽出することで不要な変数を削除します。メソッドの抽出(Extract → "Method...")にとても似ていますが、こちらは一時的な変数を削除するのが目的のようです。

使い方

  1. エディタ上で削除したい変数にカーソルを置く
  2. "Replace Temp with Query..."を実行
図35 ⁠Replace Temp with Query」ダイアログ
図35

コンストラクタをファクトリメソッドに置き換える(Replace Constructor with Factory Method)

表題の通りです。コンストラクタの代わりに専用のファクトリメソッドを追加し、それに置き換えます。

使い方

  1. 「Structureツールウィンドウ」やエディタでコンストラクタ定義が呼び出し部分を選ぶ(エディタの場合、カーソルを置く)
  2. "Replace Constructor with Factory Method..."を実行
図36 ⁠Replace Constructor with Factory Method」ダイアログ
図36

コンストラクタをビルダに置き換える(Replace Constructor with Builder)

表題の通りです。コンストラクタをビルダメソッドに置き換えます。ビルダとはリスト3のようなクラスの事です。

リスト3 ビルダの例
// 使い方
//   Foo foo = new FooBuilder().setA(10).setB(20).createFoo();
class FooBuilder {
  int a, b;

  FooBuilder setA(int a) { this.a = a; return this; }
  FooBuilder setB(int b) { this.b = b; return this; }

  Foo createFoo() { return new Foo(a, b); }
}

使い方

  1. 「Structureツールウィンドウ」やエディタでコンストラクタ定義か呼び出し部分を選ぶ(エディタの場合、カーソルを置く)
  2. "Replace Constructor with Builder..."を実行
図37 ⁠Replace Constructor with Builder」ダイアログ(クリックすると動きがわかります)

ジェネリクス化(Generify)

ジェネリクスが適用されていないコードを解析して、ジェネリクスを適用します。

使い方

  1. ジェネリクスの適用レベルに応じて、以下の方法で対象を選ぶ
    • 「Projectツールウィンドウ」でディレクトリ、パッケージ、クラスを選択
    • 「Structureツールウィンドウ」でクラス、メソッドを選択
    • エディタでクラスやメソッドにカーソルを置くか、任意の選択範囲を指定
  2. "Generify..."を実行
図38 ⁠Generify」ダイアログ
図38
※ ディレクトリ指定できる珍しいリファクタリング

マイグレーション(Migrate)

古いパッケージやクラスを新しいものに移行します。このリファクタリングの歴史はとても古くSwing 1.0.3をSwing1.1に移行するのに用いましたが、今はもう活躍する場はないでしょう。

使い方

  1. 選択状態、カーソル位置に関係なく"Migrate..."を実行
図39 ⁠Package and Class Migration」ダイアログ
図39
※ プリセットされているのは「Swing (1.0.3 -> 1.1)」のみ。

「Package and Class Migration」ダイアログで「New...」「Edit...」ボタンを押せば、独自のマイグレーション方法を作成することができます。

図40 ⁠Edit Migration Map」ダイアログ
図40

Javaに変換する(Convert to Java)

GroovyのソースコードをJavaに変換します。Android StudioがGradleサポートをする都合でGroovyをサポートしているために付いてきているリファクタリングです。

Android StudioでGroovyを使うのは一筋縄ではいかないので、ほとんど使う機会はないでしょう。

使い方

  1. 「Projectツールウィンドウ」でGroovyのソースコードを選択します(エディタの場合、Groovyのソースコードを開いておく)
  2. "Convert to Java"を実行
図41 モノは試しにbuild.gradleをJavaに変換(クリックすると動きがわかります)
※ デモで行っているだけでリファクタリングとしては無意味です。

国際化(Internationalize)

Javaのソースコード中にハードコーディングしている文字列リテラルをリソースバンドルResourceBundleに抜き出し、国際化対応(多言語対応)します。

純粋なJavaの開発ではリソースバンドルを用いて国際化を行うのが標準的ですが、Android開発では strings.xml を使うので、Android Studioでこのリファクタリングが使われることはないと思います。

使い方

  1. リソースバンドルに抜き出したい文字列リテラルにカーソルを置く
  2. "Internationalize..."を実行
図42 ⁠I18nize Hardcoded String」ダイアログ
図42

スタイルのインライン化(Inline Style)

Android固有のリファクタリングです。⁠スタイルの抽出」の逆で、レイアウトリソースのスタイル参照style属性)をインライン展開します。

使い方

  1. エディタ上でインライン化したいスタイル参照にカーソルを置く
  2. "Inline Style..."を実行
図43 ⁠Inline Android Style」ダイアログ
図43

可能ならばスタイルを使用する(Use Style Where Possible)

Android固有のリファクタリングです。レイアウトリソースから既存のスタイルに置き換え可能な部分を探し出し、それらをスタイル参照に置き換えます。⁠スタイルの抽出」と連動して実行することもできます。

図44 スタイル抽出(Extract → "Style...")時に連動するオプション
図44

使い方

  1. styles.xmlをエディタで開き、スタイル適用させたいスタイルにカーソルを置く
  2. "Use Style Where Possible..."を実行
図45 "Use Style Where Possible..."の実行例(クリックすると動きがわかります)

可能ならばRTLサポートを追加する(Add RTL Support Where Possible)

Android固有のリファクタリングです。RTL(Right-To-Left:アラビア語などのように右から左に表記すること)サポートに必要な設定を加えます。

使い方

  1. 選択状態、カーソル位置に関係なく"Add RTL Support Where Possible..."を実行
図46「Add Right-To-Left (RTL) Support...」ダイアログ
図46

まとめ

リファクタリングメニューが多くて正直うんざりもしますが、すべてを使いこなすことは稀です。筆者の経験から言えば、リネーム、抽出系など頻繁に使うのは5つ程度で、残りのメニューは存在を忘れているか、使ったとしても年に数回、もしくは数年に1回程度です。

数年に1回しか使わないリファクタリングであっても、その時はかけがえのない機能だったりします。Android Studioがどんなリファクタリングを出来るのかはサラっとでもいいので認識していると、イザというときに助かるでしょう。

リファクタリング実行も「やり直し("Undo"⁠⁠」が利くので、恐れずあれこれ試してみると良いです。ただ、何かしらのバージョン管理システムと連携している状態にしてからリファクタリングしたほうが、変更のあったファイルをすべて把握できるので精神衛生上好ましいです。

最後にEclipseのリファクタリングとの対比を表1にまとめました。Eclipseから移行した方々の参考になれば幸いです。

表1 EclipseとAndroid Studioのリファクタリングメニューの比較
Eclipseのリファクタリングメニュー「Refactor」メニューの対応項目
"移動...""Move..."
"メソッドの抽出..."Extract → "Method..."
"ローカル変数の抽出..."Extract → "Variable..."
"定数の抽出..."Extract → "Constant..."
"インライン化...""Inline..."
"ローカル変数をフィールドに変換..."Extract → "Fields..."
"匿名クラスをネストに変換...""Convert Anonymous to Inner..."
"型を新規ファイルに移動...""Move..."
"スーパークラスの抽出..."Extract → "Superclass..."
"インターフェースの抽出..."Extract → "Interface..."
"使用可能な場合にスーパータイプを使用...""Use Interface Where Possible..."
"プッシュ・ダウン...""Push Members Down..."
"プル・アップ...""Pull Members Up..."
"クラスの抽出..."Extract → "Delegate..."
"パラメーター・オブジェクトの導入..."Extract → "Parameter Object..."
"間接参照の導入..."※該当無し
"ファクトリーの導入...""Replace Constructor with Factory Method..."
"フィールドのカプセル化...""Encapsulate Fields..."
"宣言された型の一般化..."※該当無し ⁠インテンションで代用可能)
"総称型引数の推測...""Generify..."
"JARファイルのマイグレーション..."※該当無し
"スクリプトの作成..."※該当無し
"スクリプトの適用..."※該当無し
"ヒストリー..."※該当無し

おすすめ記事

記事・ニュース一覧