1文で2種類の例外をスローする

メソッドの引数を検査する時など、何種類かの例外を投げ分けたい場合があります。
これはなるべく短くしたいですね。

そこで1文で書いてみましょう。

package test;

public class Throw2Test {

    @SuppressWarnings("serial")
    static class HogeException extends Exception {/**/}
    
    @SuppressWarnings("serial")
    static class FugaException extends Exception {/**/}
    
    // 例外スローを式にするためのメソッド
    public static <A, E extends Exception> A throwE(final E e) throws E {
        throw e;
    }
    
    // 何もしない
    public static <A> void doNothing(@SuppressWarnings("unused") final A a) {/**/}
    
    private static boolean cond() {
        return true;
    }
    
    public static void main(final String[] args) throws HogeException, FugaException {
        // (1) 2文
        try {
            if(cond()) {
                throw new HogeException();
            }
            throw new FugaException();
        } catch (HogeException e) {
            e.printStackTrace();
        } catch (FugaException e) {
            e.printStackTrace();
        }
        
        // (2) throwのオペランドを条件式に
        try {
            throw cond() ? new HogeException() : new FugaException();
        } catch (Exception e) {
            // Exceptionを処理する必要がある
            e.printStackTrace();
        }
        
        // (3) 条件式の中で例外をスローする式
        doNothing(cond() ? throwE(new HogeException()) : throwE(new FugaException()));
    }

}

(1) throw は文なので、if文で条件分岐をすると2文が必要になってしまいます。
(2) throwのオペランドを条件式にすると、条件式の型が2種類の例外の共通のスーパークラスになってしまい、
Exceptionを処理する必要が生じます。
これはHogeExceptionとFugaExceptionを処理すればよかった(1)よりも重いです。
(3) そこで、実行時例外スローを式にと同様に*1例外スローを行うジェネリックなメソッドを用意します。(ここではthrowE)
メソッド呼び出しは式なので、条件式の中で使えます。
ただし条件式は文ではないので、文にするために適当なメソッド(ここではdoNothing())に渡してあげます。
以上、1文で2種類の例外をスローすることができました。

*1:今回は検査例外用に型パラメータが増えています