Inferring that what exceptions are thrown from a lambda

Zhong Yu zhong.j.yu at gmail.com
Thu Sep 5 22:02:15 PDT 2013


Observation: we can add more type parameters for the throw types:

    public interface Action<T, X1 extends Throwable, X2 extends Throwable> {
        T run() throws X1, X2;
    }

    public static <T, X1 extends Throwable, X2 extends Throwable>
    T tryRepeatedly(int maxTries, Action<T, X1,X2> action) throws X1, X2
    {
        return null;
    }

It works fine if the lambda body throws just one exception type.

If the lambda body throws two exception types, javac is not smart
enough to assign each to X1 and X2, understandably.

    // does not compile
    public void multiple0() throws ExecutionException, InterruptedException{
        String result = tryRepeatedly(10, () -> {
            if (1==2)
                throw new ExecutionException(null);
            else
                throw new InterruptedException();
        });
    }

Apparently the least upper bound is inferred

    // compiles
    public void multiple1() throws Exception{
        String result = tryRepeatedly(10, () -> {
            if (1==2)
                throw new ExecutionException(null);
            else
                throw new InterruptedException();
        });
    }

The good news is, we can always explicitly specific X1 and X2, and the
syntax looks not bad:

    // works!
    public void multiple2() throws ExecutionException, InterruptedException {
        String result = tryRepeatedly(10, (Action<String,
ExecutionException, InterruptedException>)() -> {
            if (1==2)
                throw new ExecutionException(null);
            else
                throw new InterruptedException();
        });
    }

Zhong Yu



On Thu, Sep 5, 2013 at 9:22 PM, Stuart Marks <stuart.marks at oracle.com> wrote:
> Applying this to the OP's example, this would propagate "throws
> Exception" out to the callers, forcing them to catch or to throw
> Exception themselves. That's not what the OP wanted. Instead, the
> example using a lambda that throws IOException should only be forced to
> handle or declare IOException, and the example using a lambda that
> doesn't throw any checked exceptions shouldn't have to deal with
> exceptions at all.
>
> With the new inference work in the compiler, the additional "X extends
> Throwable" type argument seems to do the trick for some common cases. (I
> tend to prefer type variable X -- "exception" -- over E, since E is
> already used for enums and for collection element types.) It doesn't
> work if the lambda throws multiple different checked exception types.
> For example, the following doesn't work:
>
>      public void multiple() throws ExecutionException,
> InterruptedException {
>          String result = tryRepeatedly(10, () -> {
>              if (/*condition*/)
>                  throw new ExecutionException(null);
>              else
>                  throw new InterruptedException();
>          });
>      }
>
> Here, the compiler infers the least upper bound for the lambda's
> exception type, which in this case is Exception, so that's what has to
> be listed in the throws clause instead of listing multiple exception
> types. Oh well.
>
> s'marks
>
>
>
> On 9/4/13 7:22 PM, Howard Lovatt wrote:
>> It is generally easier to do this:
>>
>>      public interface Action<T> {
>>           T run() throws Exception;
>>       }
>>
>> Which is what Callable does, infact the above is Callable apart from
>> the name changes (Callable -> Action, call -> run).
>>
>>
>> On 5 September 2013 06:11, Stuart Marks <stuart.marks at oracle.com
>> <mailto:stuart.marks at oracle.com>> wrote:
>>
>>     On 8/31/13 11:04 AM, Esko Luontola wrote:
>>     > But if the lambda doesn't thrown anything, the compiler thinks
>>     that the
>>     > method may throw the most generic exception. The following code
>>     fails to
>>     > compile with "error: unreported exception Throwable; must be
>>     caught or
>>     > declared to be thrown"
>>     >
>>     >       public void doesNotCompile() {
>>     >           String result = Resilient.tryRepeatedly(10, () ->
>>     "result");
>>     >       }
>>
>>     A change to support this went in fairly recently. This now
>>     compiles for
>>     me using JDK 8 b105. It fails with the error you mention when using
>>     older builds, e.g., JDK 8 b88, which is one I happened to have lying
>>     around. (Note, I am referring to JDK 8 builds, not Lambda builds.)
>>
>>     I believe that if a lambda throws no checked exceptions, and its
>>     functional interface method is declared "throws E", then E is now
>>     inferred to be RuntimeException.
>>
>>     s'marks
>>
>>
>>
>>
>> --
>>   -- Howard.
>
>


More information about the lambda-dev mailing list