第1章 ラムダ式とは : 問題 6 : ラムダ式でチェック例外を隠す
問題 6
Runnable
のrun
メソッドはチェック例外をスローできないため、ラムダ式で簡潔に表すには不便なことが多い。
例えば、以下はコンパイルエラーになってしまう。
new Thread(() -> { System.out.println("Zzz"); Thread.sleep(1000); //← InterruptedException の可能性 }).start();
全てのチェック例外をキャッチしてチェックされない例外に変更するuncheck
メソッドを書け
解答
まずRunnable
に代わり、例外をスローするrun
メソッドを持つ関数型インターフェースを定義する。
@FunctionalInterface public interface RunnableWithException { public void run() throws Exception; }
uncheck
メソッドは、次のようになる。
public static Runnable uncheck(RunnableWithException func) { return new Runnable() { public void run() { try { func.run(); } catch (Exception ex) { throw new RuntimeException(ex); } } }; }
ここでラムダ式を使って書くと、uncheck
メソッドはより簡潔になる。
public static Runnable uncheck(RunnableWithException func) { return () -> { try { func.run(); } catch (Exception ex) { throw new RuntimeException(ex); } }; }
問題文のコードにuncheck
メソッドを適用すると、コンパイルエラーが解消する。
new Thread(uncheck(() -> { System.out.println("Zzz"); Thread.sleep(1000); })).start();
さらに問題
uncheck
メソッドの引数にCallable<Void>
が使用できないのはなぜか?
解答
関数型インターフェースRunnableWithException
を導入しなくても、uncheck(Callable<Void>)
メソッドは書ける。
でもCallable<Void>
だと、最後に "return null;
" を記述しないとコンパイルエラーになってしまうからです。
この問題だと
new Thread(uncheck(() -> { System.out.println("Zzz"); Thread.sleep(1000); return null; //← この行が余計! })).start();
というふうに、余計なreturn
文が必要になる。
これはVoid
クラスが
実体のない
void
キーワードを表す Pseudo-Type