Ganymedeのテンプレートを使う

Eclipse Ganymedeでテンプレートがかなり便利になりました。
具体的には

  • コンテキストが細かく指定できるようになった
  • 変数の属性が指定できるようになった
    • 引数とか型とか
  • 別のところに命令を出せるようになった
    • インポートの追加など

あたりがパワーアップしてる模様。

テンプレートは Preferences の Java > Editor > Templates で編集できます。

if (hoge == false) ...

まずは簡単なのから。if (!hoge) が読みにくいので if (hoge == false) と書くスタイルにやっと慣れてきましたが、少しでもタイプ量減らしつつ頭の中を整理するためにこんなテンプレート作ってます。

if (${condition:var(boolean)} == false) {
    ${cursor}
}

このうち、${xxx:var(boolean)}はboolean型の変数が勝手に代入され、${cursor}はEnterでテンプレートの挿入を確定した際にカーソルが自動的にそこに行くという指定です。ちなみに、テンプレートを選択した瞬間は "${condition:..}"の位置に選択が来てるので、

  1. テンプレートを選択する
  2. 条件式をその場で入力する
  3. Enterを押す
  4. 処理を書く

という操作をカーソルの手動操作なしに行うことができます。

コンテキストは"Java statements"が適切でしょう。

もとPerlの人なので、このテンプレートには"unless"という名前をつけてます。

null検査

地味にめんどくさいnull検査。これもテンプレート化すると楽です。

if (${param:localVar(java.lang.Object)} == null) {
    throw new NullPointerException("${param}"); //$$NON-NLS-1$$
}

このうち、${param:localVar(java.lang.Object)}はローカル変数の中からObject型のサブタイプであるものが選択され、テンプレートを選んだ瞬間にローカル変数のプロポーザルが出ます。それで、ローカル変数を選択して確定すると"${param}"のところにローカル変数名が自動的に挿入されます。
この操作、なれると毎秒2個くらい書けるようになります。

ついでに、Commons系を使うとかユーティリティメソッドを用意するとかで、null検査以外の簡単な引数検査もテンプレート化しておくと楽です。私の環境だと、not null, not contains null, not empty string, not empty collection, not empty map, not negativeあたりがすごい速さで書けます。

new Exception with cause

IOExceptionのコンストラクタを見ると、Throwableをとるやつがなくてイラっとする。

throw (${Exception}) new ${Exception}().initCause(${cause:localVar(java.lang.Throwable)});

この${Exception}は特に制約のない変数で、ここにIOExceptionなどの例外型を入れます。${cause:localVar(java.lang.Throwable)}の部分は、Throwable型の何かが入ります。つまり、catch節で使うと、高い確率でcatchした例外を入れてくれるので便利。

org.slf4j.Logger

Loggerのフィールドも宣言するのめんどくさいですよね…

private static final ${Logger:newType(org.slf4j.Logger)} LOG =
	${LoggerFactory:newType(org.slf4j.LoggerFactory)}
        .getLogger(${enclosing_type}.class);

${xxx:newType(aaa.bbb.Ccc)}と書くと、aaa.bbb.Cccのように限定名で書いた型を勝手にインポートして単純名に置き換えてくれます。さらに${enclosing_type}は自分のクラス名が入ります。slf4jのLoggerを使う分には大体このパターンで困らないかと。
これはメンバとして宣言するので、コンテキストを"Java type members"にしておくといいです。

readObject, writeObject, readResolve

Javaのシリアライゼーションで使う特殊なメソッド、readObject, writeObject, readResolveは月に2〜3回も書かないのでたいてい忘れてしまいますが、書かないとひどいことになったりします。ということで、テンプレート化してます。

private void readObject(
        ${ObjectInputStream:newType(java.io.ObjectInputStream)} stream)
        throws ${IOException:newType(java.io.IOException)},
        ClassNotFoundException {
    stream.defaultReadObject();
    // TODO readObject
}

private void writeObject(
        ${ObjectOutputStream:newType(java.io.ObjectOutputStream)} stream)
        throws ${IOException} {
    stream.defaultWriteObject();
    // TODO writeObject
}

private Object readResolve() {
    return this;
}

特に新しいことはありません。メンバとして宣言するので、コンテキストを"Java type members"にしておくといいです。

assertThat

assertThatを使うようになったのですが、"import static org.hamcrest.Matchers.*;"を書き足すのが面倒です。

そこでこんなの。紙面の問題で3行にしてますが、1行で書いたほうがいいです。

${assert:importStatic('org.junit.Assert.*')}
${matchers:importStatic('org.hamcrest.Matchers.*')}
assertThat(${cursor});

Contextは"Java statements"がいいです。

これを書くと、assertThatで補完(わざわざテンプレートを指定)した時に"import static org.junit.Assert.*;", "import static org.hamcrest.Matchers.*;"を勝手に追加してくれます。

@Before, @After

もう解説書くのが面倒になってきた。

/**
 * テストを初期化する。
 * @throws Exception 例外が発生した場合
 */
@${Before:newType(org.junit.Before)}
public void setUp() throws Exception {
}

/**
 * テストの情報を破棄する。
 * @throws Exception 例外が発生した場合
 */
@${After:newType(org.junit.After)}
public void tearDown() throws Exception {
}

Javadoc関連

Javadocを書く速度は、エディタテンプレートを駆使することで2〜3倍くらいまで上げられます。
手元の環境で、Contextが"Javadoc"になってるもののうち、自分で足したであろうものをつらつらと。

まずは簡単なショートカット記号。

名前 内容
@ @
< &lt;
> &gt;
@this {@code this}
@null {@code null}
@true {@code true}
@false {@code false}

次に@returnで特殊な値を返す場合。

名前 内容
@returnsNull ${cursor}場合は{@code null}
@returnsBoolean ${cursor}場合は{@code true}、そうでない場合は{@code false}

最後にRuntimeExceptionの@throws周り。

名前 内容
@NullPointerException @throws NullPointerException 引数に{@code null}が含まれる場合
@IllegalArgumentException @throws IllegalArgumentException 引数${cursor}場合
@IllegalStateException @throws IllegalStateException ${cursor}

上記では省略しましたが、HTMLのタグもいくつか追加してます。pとかpreとか。
おそらくこれはGanymedeじゃなくても動きます。

まとめ

テンプレートを使うとそれなりに似たようなコードを素早く書くことができるようになります。
ただ、やりすぎると似たようなコピーが大量に出来上がるので、設計で何とかなる部分はなんとかしたほうがよさげ。

ちなみに、プロジェクトの特性に合わせて別のテンプレート作ることもあります。なんかオススメなのあったら教えてください。