Status Code 303 - See Other

サーバサイド、iOS・アンドロイドアプリ、インフラレベルの話まで幅広くやってます。情報の誤りや指摘・意見などは自由にどうぞ。

Lombok ライブラリ - その他

主記事
Lombok ライブラリ - Status Code 303 - See Other

この記事では、クラスとフィールド以外に関連するアノテーションを記述。
(記事執筆時のバージョン :v1.16.6)

(更新中)

データ同期

@Synchronized

このアノテーションメソッドに設定すると、メソッドに synchronized キーワードを設定したときとほとんど同等動きをする。
プライベートな内部インスタンスを除いては、管轄外のコードがスレッド操作に割り込まないように、そのインスタンスをロックする。

staticでないメソッドには $lock、static なメソッドには $Lock という名称のフィールド変数がロックのために使われる。
これらは、必要であったり、存在しなかった場合のみ作成され、このフィールドはシリアライズ可能である。

オプション

value
ロックに利用するフィールド名を異なる名前に設定したい場合に使用する。 注意事項として、コンパイル時までにその変数を作成しなければならず、存在していない場合はコンパイルエラーになる。 (デフォルトコンストラクタと同じように、自動生成されるのは何も指定しなかったときのみ)

型推論

val

ローカル変数にのみ使用可能であり、初期化の式から型を推測する。
また、val を定義したローカル変数は、final になる。
例:

val x = 10.0;
val y = new ArrayList<String>();

と記述すれば、 val は以下と同等とみなされる。

final double x = 10.0;
final ArrayList<String> y = new ArrayList<String>();

なお、あまりそうは見えないかもしれないが val はアノテーション型である。(正確にはシンタックスシュガーらしい)
なぜなら、 val x = 10.0; と記述すれば、Lombok は @val final int x = 10; にコードを変換するから。
詳細はこちら(val)

オプション

なし。

ツールに対する適用外設定

@Generated

いずれは、Lombok が生成したメソッドやクラスに自動的に付加するアノテーション
全てのコードスタイルチェックツールやバグ発見ツールに対して、これらのコードを無視させるために使用する。

オプション

なし。

注釈

このアノテーションが導入されたバージョン 1.16.2 では、実際は Lombok はこのアノテーションを付加できていない。
このため、広く普及している Lombok.jar がこの機能を持つように準備中であり、これらは近い将来使用できるようになるだろう。

メソッドパラメータの null チェック自動生成

@NonNull

詳細は、メソッド @NonNull 参照。
注意点として、メソッドのパラメータにこれを指定すると、Lombok によって生成メソッドでなくても適用される。

メソッドやローカル変数にも設定できるらしいが、その場合の記載はない。

リソース解放処理の自動生成

@Cleanup

何が起こったかに関係なく、ローカル変数がそれらの close メソッド呼び出しによってリソースの解放を保証する宣言。
ローカル変数の有効範囲にある全ての命令文を包括した try 文を実装することにより、リソースを解放する。
詳細なドキュメントこちら(@Cleanup)。

例:

 public void copyFile(String in, String out) throws IOException {
     @Cleanup FileInputStream inStream = new FileInputStream(in);
     @Cleanup FileOutputStream outStream = new FileOutputStream(out);
     byte[] b = new byte[65536];
     while (true) {
         int r = inStream.read(b);
         if (r == -1) break;
         outStream.write(b, 0, r);
     }
 }

これらの宣言が Lombok によって以下の処理に変換される。

 public void copyFile(String in, String out) throws IOException {
     @Cleanup FileInputStream inStream = new FileInputStream(in);
     try {
         @Cleanup FileOutputStream outStream = new FileOutputStream(out);
         try {
             byte[] b = new byte[65536];
             while (true) {
                 int r = inStream.read(b);
                 if (r == -1) break;
                 outStream.write(b, 0, r);
             }
         } finally {
             if (out != null) out.close();
         }
     } finally {
         if (in != null) in.close();
     }
 }
オプション

value(デフォルト:close)
リソース解放メソッドが close ではないときにそのメソッド名を指定する。 ただし、指定するメソッドは1つもパラメータを持たないものでなければならない。

チェック例外 → 実行時例外変換

@SneakyThrow

Java では、メソッド処理内にチェック例外を生成し得る命令が記述された場合、その例外に対処しなければならない。
(try-catch 文で例外をキャッチするか、メソッド呼び出し元に伝播させるなら throws 宣言を使ったりする)
しかし、このアノテーションメソッドに記述すると、本来行うはずのチェック例外に対処しなくても良くなる。

このアノテーションは、内部的にオプション(value)に指定されたチェック例外(複数可)を
RuntimeException もしくは他の実行時例外にラップしている。こうして、チェック例外が実行時例外内に隠れるため、
本来 JVM が行うはずだった、チェック例外における一貫性チェックを回避している。

例:
下記のバイト列を特定の文字コードから String インスタンスを生成するコンストラクタはチェック例外である
UnsupportedEncodingException をスローするため、本来は何かしら対処をしなければならない。
しかし、以下の例では、これを省略してもプログラムは正常に動作する。

 @SneakyThrows(UnsupportedEncodingException.class)
 public void utf8ToString(byte[] bytes) {
     return new String(bytes, "UTF-8");
 }

これは、Lombok が上記コードを内部的に下記のように変換しているから。

public void utf8ToString(byte[] bytes) {
     try {
         return new String(bytes, "UTF-8");
     } catch (UnsupportedEncodingException $uniqueName) {
         throw useMagicTrickeryToHideThisFromTheCompiler($uniqueName);
         // This trickery involves a bytecode transformer run automatically during the final stages of compilation;
         // there is no runtime dependency on lombok.
     }
}

なお、元のコードと同じ動きを保証するために発生する条件では、本来スローされるべき例外がスローされる。

import java.text.SimpleDateFormat;
import lombok.SneakyThrows;

public class Main {
	@SneakyThrows
	public static void main(String[] args) {
		System.out.println(new SimpleDateFormat("yyyyMMdd").parse("aaaaa")); // 意図的に例外(ParseException)を発生させる
	}
}

出力結果。

Exception in thread "main" java.text.ParseException: Unparseable date: "aaaaa"
	at java.text.DateFormat.parse(DateFormat.java:366)
	at Main.main(Main.java:8)

詳細はこちら(@SneakyThrows)

オプション

value(デフォルト:java.lang.Throwable.class)
メソッド呼び出し元にこっそりスローしたい例外型を指定する(複数可能)。