Inferring that what exceptions are thrown from a lambda

Zhong Yu zhong.j.yu at gmail.com
Sun Sep 1 10:13:40 PDT 2013


In this example

     () -> {  throw new IOException("dummy exception"); }

the lambda body may throw unchecked exception as well; if we take the
least-upper-bound of all exceptions that may be thrown, it'd be
Throwable. That's not reasonable; therefore the story is deeper than
just least-upper-bound.

Previously I submitted a proposal, and Maurizio said he's working a solution too
http://mail.openjdk.java.net/pipermail/lambda-dev/2013-February/007991.html
what happened to that?

Zhong Yu



On Sun, Sep 1, 2013 at 11:07 AM, Brian Goetz <brian.goetz at oracle.com> wrote:
> First, let's note this has nothing directly to do with lambdas; the same
> thing happens with anonymous classes.
>
> This is purely a limitation of how generics interact with exceptions
> (which is to say, not so well.)
>
> If you have:
>
>         public interface Action<T, E extends Throwable> {
>             T run() throws E;
>         }
>
> This means: for every Action, there must be exactly one type, bounded by
> Throwable, represented by E.  There is no way to parameterize Action
> with an E that means "just kidding, I don't throw anything."
>
> Note also that there's no way for Action to work nicely with something
> that throws more than one unrelated exception (say, IOException or
> SQLException) without just taking their least-upper-bound (here,
> Exception).  Another restriction of the "one type variable, one type"
> rule of generics.  Again, nothing to do with lambda, except that lambda
> exposes more cases where you'd like to do this.
>
> There have been a number of proposals to address this weakness, under
> various names (exception transparency, variadic generics) which would
> let a type variable E, instead of referring to exactly one type, refer
> to zero or more types.  These were explored during the development of
> Project Lambda and deemed to be a poor balance of complexity to power,
> and so we did not move forward on any of these proposals.  (Search the
> list archives for the details.)
>
> So, tl;dr version:
>   - A generics problem, not a lambda problem
>   - Not a new problem
>   - Possible solutions explored and rejected
>
>
>
> On 8/31/2013 2:04 PM, Esko Luontola wrote:
>> Given an interface and method like this:
>>
>>       public interface Action<T, E extends Throwable> {
>>           T run() throws E;
>>       }
>>
>>       public static <T, E extends Throwable> T tryRepeatedly(int
>> maxTries, Action<T, E> action) throws E {
>>           // ...
>>       }
>>
>> If the method is provided a lambda that throws e.g. an IOException, the
>> compiler figures out correctly that the method may also throw
>> IOException and requires that exception to be rethrown:
>>
>>       public void compiles() throws IOException {
>>           String result = Resilient.tryRepeatedly(10, () -> {
>>               throw new IOException("dummy exception");
>>           });
>>       }
>>
>> 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");
>>       }
>>
>> So the developer must declare the surrounding method to throw an
>> exception that may never be thrown:
>>
>>       public void compilesButUndesirable() throws Throwable {
>>           String result = Resilient.tryRepeatedly(10, () -> "result");
>>       }
>>
>> Is this as planned or is it a bug? Is there a workaround? I would expect
>> that since the compiler can figure out what exception the first case
>> throws, it should also figure out that the latter case doesn't throw
>> checked exceptions.
>>
>


More information about the lambda-dev mailing list