Inferring Exception type of a lambda body

Zhong Yu zhong.j.yu at
Tue Feb 5 10:16:21 PST 2013

Say we have a functional interface in which the method throws a type variable E

    interface Action<E extends Throwable>
        void doIt() throws E;

and a generic method that invokes Action<E> and passes through E

    <E extends Throwable> void invoke(Action<E> action) throws E
        action.doIt(); // throws E

It works for lambdas that throw checked exceptions:

    // compiles, E is inferred as Exception
    void test1() throws Exception
        invoke( ()->{ throw new Exception(); } );

But it doesn't work for unchecked exceptions:

    // fails, E is inferred as Throwable
    void test2()
        invoke( ()->{ } );
        // or invoke( ()->{ throw new RuntimeException(); } );
        // or invoke( ()->{ throw new Error(); } );

Apparently, if the lambda body throws only unchecked exceptions, javac
does not set a lower bound on E, so E is chosen to be its upper bound

I'd argue that Throwable is too broad for E, and E should have a lower
bound. Since any method can throw Error, Action.doIt() actually throws
Error|E, which should be a super type of unchecked exceptions, i.e.
Error|E :> Error|RuntimeException, so we can argue that E :>

My suggestion for the inference rule is, very simplistically,

If E has not been inferred from previous steps, and E is in the throw
clause, and E has an upper constraint E<<X,
    if X:>RuntimeException, infer E=RuntimeException
    otherwise, infer E=X. (X is an Error or a checked exception)

Zhong Yu

More information about the lambda-dev mailing list