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