Inferring that what exceptions are thrown from a lambda

Brian Goetz brian.goetz at
Sun Sep 1 09:07:54 PDT 2013

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