( ꒪⌓꒪)( ꒪⌓꒪)
( ꒪⌓꒪)( ꒪⌓꒪)
Lombokアノテーションのメモ
Javaのコンパイル時に定型コードを自動生成してくれるLombokをいろいろ触ってみたのでメモする。
@NonNull
メソッドの引数に付与してnullチェックを生成する。
メソッドの先頭でnullかどうか確認し、nullの場合はNullPointerExceptionをthrowする。コンストラクタの場合はsuper()やthis()の呼び出しの後にチェックされる。
生成前
public void hoge(@NonNull Object fuga){ System.out.println(fuga); }
生成後
public void hoge(@NonNull Object fuga) { if (fuga == null) { throw new NullPointerException("fuga is marked @NonNull but is null"); } else { System.out.println(fuga); } }
@Cleanup
ローカル変数の宣言に付与して、スコープを抜ける前にオブジェクトのクリーンアップ処理を追加する。
具体的にはtry-finally節の追加とfinally節中にclose()メソッドの呼び出しを追加する。@Cleanupの引数にメソッド名を文字列で指定して、close()メソッド以外を呼ぶこともできる。
生成前
public void hoge() throws IOException { @Cleanup BufferedReader reader = new BufferedReader(new FileReader("testfile.txt")); System.out.println(reader.readLine()); }
生成後
public void hoge() throws IOException { BufferedReader reader = new BufferedReader(new FileReader("testfile.txt")); try { System.out.println(reader.readLine()); } finally { if (Collections.singletonList(reader).get(0) != null) { reader.close(); } } }
@Getter/@Setter
フィールドに付与してgetterとsetterを生成する。メソッド名はフィールド名の先頭を大文字にしてget/setをつけたものが生成されるが、フィールドの型がbooleanの場合、getterメソッド名はgetではなくisをつけた名前になる。
可視性はデフォルトでpublicになるが、@Getter/@Setterの引数にAccessLevel.*を指定すると変更することができる。
クラス定義にアノテーションを付与した場合、インスタンスフィールド全てが生成対象になる。 生成したくないフィールドがある場合、AccessLevel.NONEをフィールドに付与すると生成されなくなる。
生成前
@Setter @Getter private int hoge; @Getter(AccessLevel.PACKAGE) private boolean fuga;
生成後
private int hoge; private boolean fuga; public void setHoge(int hoge) { this.hoge = hoge; } public int getHoge() { return this.hoge; } boolean isFuga() { return this.fuga; }
@ToString
クラス定義に付与して、toString()メソッドの実装を生成する。 デフォルトでは、クラス名(フィールド名1=値, フィールド名2=値,...)形式の文字列を返す。アノテーションの引数にincludeFieldNames=falseを追加するとフィールド名を取り除くことができ、callSuper=trueを指定すると親クラスのtoString()メソッドの結果を含めることができる。
デフォルトではインスタンスフィールド全てが文字列の生成対象となる。除外したい場合はフィールドに@ToString\.Excludeアノテーションを付与する。もしくはクラス定義の@ToStringにonlyExplicitlyIncluded=trueを指定して表示したいフィールドのみ@ToString\.Includeを付与することで、表示するフィールドを制御できる。
引数なしのインスタンスメソッドに@ToString\.Includeを付与することで、メソッドの実行結果も生成文字列に含めることもできる。
生成前
@ToString(callSuper=true) public class Sandbox { private int hoge; private boolean fuga; }
生成後
public String toString() { return "Sandbox(super=" + super.toString() + ", hoge=" + this.hoge + ", fuga=" + this.fuga + ")"; }
@EqualsAndHashCode
equals()とhashCode()メソッドを生成する。
生成前
@EqualsAndHashCode public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
長いので省略。equals()はフィールド同士をequals()メソッドで比較する。
コンストラクタ生成(@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor)
@NoArgsConstructor
引数なしのコンストラクタを生成する。
未初期化のfinalフィールドを持つ場合コンパイル時エラーとなるが、force=trueを指定した場合は0かfalseかnullで初期化される。@NonNullを付与したフィールドがあった場合でもnullチェック処理は生成されないので注意が必要。
生成前
@NoArgsConstructor() public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
public class Sandbox { @NonNull private Integer hoge; private boolean fuga; public Sandbox() { } }
@RequiredArgsConstructor
すべての初期化されていないfinalフィールド・@NonNullが付与されたフィールドを引数に持つコンストラクタを生成する。引数の順序はクラス内の出現順と同じ。
@NonNullのnullチェックは生成される。
生成前
@RequiredArgsConstructor() public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
public class Sandbox { @NonNull private Integer hoge; private boolean fuga; public Sandbox(@NonNull Integer hoge) { if (hoge == null) { throw new NullPointerException("hoge is marked @NonNull but is null"); } else { this.hoge = hoge; } } }
@AllArgsConstructor
全てのフィールドを引数に持つコンストラクタを生成する。
@NonNullのnullチェックは生成される。
生成前
@AllArgsConstructor() public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
public class Sandbox { @NonNull private Integer hoge; private boolean fuga; public Sandbox(@NonNull Integer hoge, boolean fuga) { if (hoge == null) { throw new NullPointerException("hoge is marked @NonNull but is null"); } else { this.hoge = hoge; this.fuga = fuga; } } }
@Data
@ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructorを指定した場合と同じ。
生成前
@Data public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
長いので省略。生成されたメソッドは次の通り。
@RequiredArgsConstructorpublic Sandbox(@NonNull Integer hoge)
@Getter/@Setterpublic Integer getHoge()public boolean isFuga()public void setHoge(@NonNull Integer hoge)public void setFuga(boolean fuga)
@EqualsAndHashCodepublic boolean equals(Object o)protected boolean canEqual(Object other)public int hashCode()
@ToStringpublic String toString()
@Value
@Dataをimmutableにしたもの。すべてのフィールドはprivate finalに設定され、Setterは生成されない。
クラスにもfinalが設定されるが@NonFinalを指定していると設定されない。 生成されるメソッドが先に定義されていた場合は、メソッドが生成されないだけでエラーは発生しない。
生成前
@Value public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
こちらも省略。
@Builder
クラス定義に付与してBuilderクラスを生成する。生成するコードは次の通り。
Innerクラスの
${クラス名}Builderを生成するBuilderインスタンスを返す
builder()メソッドを生成する。${クラス名}Builderに次のメソッド・フィールドを生成する
生成前
@Builder public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
public class Sandbox { @NonNull private Integer hoge; private boolean fuga; Sandbox(@NonNull Integer hoge, boolean fuga) { if (hoge == null) { throw new NullPointerException("hoge is marked @NonNull but is null"); } else { this.hoge = hoge; this.fuga = fuga; } } public static Sandbox.SandboxBuilder builder() { return new Sandbox.SandboxBuilder(); } public static class SandboxBuilder { private Integer hoge; private boolean fuga; SandboxBuilder() { } public Sandbox.SandboxBuilder hoge(Integer hoge) { this.hoge = hoge; return this; } public Sandbox.SandboxBuilder fuga(boolean fuga) { this.fuga = fuga; return this; } public Sandbox build() { return new Sandbox(this.hoge, this.fuga); } public String toString() { return "Sandbox.SandboxBuilder(hoge=" + this.hoge + ", fuga=" + this.fuga + ")"; } } }
@Synchronized
メソッドに付与して、指定したオブジェクトでロックするsynchronizedブロックを追加する。
デフォルトの場合、インスタンスメソッドは$lockフィールド、クラスメソッドは$Lockクラスフィールドが使用される。 存在しない場合はprivateで作成される。
別のフィールドでロックしたい場合は@Synchronizedの引数にフィールド名を文字列で指定する。
生成前
@Synchronized public void hoge(){ System.out.println("hoge"); } @Synchronized public static void fuga(){ System.out.println("fuga"); }
生成後
private final Object $lock = new Object[0]; private static final Object $LOCK = new Object[0]; public void hoge() { synchronized(this.$lock) { System.out.println("hoge"); } } public static void fuga() { synchronized($LOCK) { System.out.println("fuga"); } }
@Log
クラス定義に付与すると、static finalなlogフィールドを生成し指定したロガーで初期化する。各ロガー実装に応じたアノテーションが用意されている。
生成前
@Log public class Sandbox { @NonNull private Integer hoge; private boolean fuga; }
生成後
private static final Logger log = Logger.getLogger(Sandbox.class.getName());
参考
はてなブログおみくじ2014
はてなブログおみくじ2014
あけましておめでとうございます。
~/.ssh/known_hostsから指定したホストの鍵を取り除く
知らなかったのでメモ。
$ ssh-keygen -R (hostname)
3月が延長されたと聞いて

3月を延長するのをやめました(復旧済み) - はてなブログ開発ブログ
記事のURLは2013/04/01になっていて悲しい。
rbenv, ruby-build導入メモ
複数のバーションのrubyを切り替えられるようにするrbenvとruby-buildをインストールしてみたのでメモします。
まずは、homebrewでコマンド本体をインストールします。
% brew install rbenv ruby-build
インストール途中にシェルの設定が書かれているのでこの通り追加します。PATHの設定、補完関数の追加、rbenvコマンドの再定義などをしているようです。
2行目を~/.zshrcに追加すればいいのですが、zshの場合は$(rbenv init -)を$(rbenv init - zsh)に変えないとエラーが出るので注意です。
To enable shims and autocompletion add to your profile: if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi
設定を読み直してエラーを吐かなければOKです。
% source .zshrc
次にRubyのビルドのための準備です。OSX標準のopensslとreadlineはアレらしいのでhomebrewからインストールします。
% brew install openssl % brew link openssl % brew install readline % brew link readline
installサブコマンドを-l付きで実行するとインストール可能なrubyのバージョンが表示されるので、ここから選択します。JRubyも入っているんですね。
% rbenv install -l Available versions: (以下長いので適当に抽出) 1.8.6-p420 1.8.7-p249 1.8.7-p302 1.8.7-p370 1.9.3-p286 jruby-1.7.0 maglev-1.0.0 rbx-1.2.4 rbx-2.0.0-dev ree-1.8.7-2012.02
先ほどインストールしたopensslとreadlineにリンクさせる為にオプションを付けてインストールコマンドを叩きます。
% CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline) --with-openssl-dir=$(brew --prefix openssl)" rbenv install 1.9.3-p286
rbenvのrubyの切り替え方法は以下の3つがあります。
- global そのユーザで有効
- local そのディレクトリで有効
- shell そのシェルで有効
今回は普段使うバージョンの選択なのでglobalサブコマンドでバージョンを指定します。
% rbenv global 1.9.3-p286 % ruby --version ruby 1.9.3p286 (2012-10-12 revision 37165) [x86_64-darwin12.2.1]
1.9.3p286を使うことができています。
仕組みはこちらで解説されていますが、~/.rbenv/versions以下に各バージョンのバイナリをインストールし、~/.rbenv/shims/に使用するバージョンのシンボリックリンクをおいてPATHを通しているようです。
またgemsetは上の3つの切り替え方法とは関係なく、現在選択しているrubyのバージョンに紐付いているようです。gemで実行コマンドをインストールするような操作をした場合、rbenv側で対応するシンボリックリンクを作成しなければならないため、コマンド実行前に
% rbenv rehash
を実行する一手間が必要になります。

