Javaのカレンダー | Advent Calendar 2021の14日目の記事です
※ 北斗の拳のようなタイトルになってしまって申し訳ありません
概要
@SneakyThrows
を使って検査例外(チェック例外)を非検査例外(非チェック例外)?に投げ直すやり方
Stream API では、検査例外は try - catch で握る必要があるので、非検査例外にすることでコードをシンプルに保ちます
参考
やり方
before
void tryCatch() {
Stream.of("2021/12/22", "2021/12/23", "a").map(s -> {
try {
return new SimpleDateFormat("yyyy/MM/dd").parse(s);
} catch (ParseException e) {
return new RuntimeException(e);
}
}).forEach(System.out::println);
}
after
void sneakyThrows() {
Stream.of("2021/12/22", "2021/12/23", "a").map(this::parse).forEach(System.out::println);
}
@SneakyThrows
Date parse(String s) {
return new SimpleDateFormat("yyyy/MM/dd").parse(s);
}
説明
Stream API の中間操作で検査例外が発生する場合は、try - catch で例外を受け付ける必要があるため、冗長な例外処理を書く必要があります。
これに対応するため、検査例外を投げる処理を別のメソッドに抽出して、@SneakyThrows
アノテーションをつけることで検査例外の例外処理のコードを省略するテクニックです。
ポイント
- 別メソッドに抽出しているため、コードの行数は変わらない。もしくは増える場合がある。が、可読性は増す。
- 必要に応じて、呼び出しの大元で適切な例外処理を書くことは当然必要。スタックトレースを出せば、どこで発生したかはわかるため不安はない。
- SpringBoot であれば
@RestControllerAdvice
がオススメ
- SpringBoot であれば
- 中間操作で例外を握りつぶす(イレギュラーな状態でも処理を継続したい)必要がある場合は、 try - catch を利用して例外処理を書きます
-
@SneakyThrows
は、検査例外を非検査例外に詰め直しているわけではない(javac 時に一時的に検査例外として認識されないようにしている)ので、投げられる例外は、検査例外になっている(そして、UndeclaredThrowableExceptionになってしまう?ちょっと自信なし) - 別メソッドに切り出す必要もないほどのコード(例のコードもそうではあるが)
jOOQ
の Unchecked.throwChecked() を検討してもよい