netty のコードで結構前に見かけて覚えていたけど、完全に失念してて悔しかったので、メモ
呼び出し側にとってはこういうコード書かれたらかなり邪悪だと思う。
こんな感じのコード
import java.io.IOException; import java.util.stream.Stream; class Rethrow { interface IOOp { void run() throws IOException; } static void io(IOOp op) { try { op.run(); } catch (IOException e) { rethrow(e); } } static void rethrow(Throwable throwable) { rethrow0(throwable); } @SuppressWarnings("unchecked") static <T extends Throwable> void rethrow0(Throwable throwable) throws T { throw (T)throwable; } public static void main(String... args) { Stream.of("catch me if you can", "(☝՞ਊ ՞)☝ウェーイwwwみてるー?") .map(IOException::new) .forEach(e -> io(() -> { throw e; })); } }
rethrow
と rethrow0
の組み合わせがポイントになる…なお、言語仕様を詳しく調べてないので、コンパイルエラーにならない理由をうまく説明できない
実行結果はこちら
IOException
により、 main
が終了していることがわかる
なお、 Stream
の部分を try
/catch(IOException e)
で囲むと、コンパイルエラーになる
したがって、このコードは検査例外を非検査で投げるが Exception
/Throwable
以外の非検査例外では catch
できなくなるので注意が必要