Inferring that what exceptions are thrown from a lambda
Brian Goetz
brian.goetz at oracle.com
Sat Sep 7 07:32:55 PDT 2013
Because it would have been cruel to make people write:
Function<String,String,RuntimeException> f = String::toUpperCase;
every time the type was explicitly specified, you'd have to write out
the value of the exception parameter, even in the 99.99% of cases where
no exception was thrown. (People do write out instantiated types of
functional interfaces sometimes!) And, even if you're not writing out
the instantiated type, but including it in an API, you still have to say
Function<T,U,X> in every place the type is named, and a method that
takes a SAM needs to acquire an inferred <X extends Throwable> generic
parameter, meaning more declaration noise for a feature most people
don't want. AND, you're still subject to the fact that if you want to
throw two unrelated exceptions, you're screwed. So its an incomplete
solution that impose syntactic overhead on the vast majority of cases.
The EG further discussed (and instantly rejected) pairing each
functional interface with an "exceptional" counterpart
(ExceptionalFunction<T,U,X>) and rejected it because (a) really, we
should double the number of functional interfaces for this? and (b) it
still only works if you have exactly one unrelated exception thrown.
Machinery to address these limitations was also explored and rejected
(see the archive for discussions.)
So, when you say harmless, you really mean awful :)
On 9/7/2013 4:06 AM, Millies, Sebastian wrote:
> Why do the common interfaces from java.util.function do not utilize this
> parametric exception type? For example Consumer? So that one
> could write things like this:
>
> void appendAll(Iterable<String> values, Appendable out)
> throws IOException
> {
> values.forEach(s -> out.append(s));
> }
>
> Which currently fails to compile because accept() has no exception param.
>
> It would seem useful to introduce such parameters. It would also be
> harmless, because all lambdas currently passed to these interfaces don't
> throw exceptions, and RuntimeException would always be inferred.
>
> -- Sebastian
>
>> -----Original Message-----
>> From: lambda-dev-bounces at openjdk.java.net [mailto:lambda-dev-
>> bounces at openjdk.java.net] On Behalf Of Howard Lovatt
>> Sent: Saturday, September 07, 2013 4:21 AM
>> To: Stuart Marks
>> Cc: lambda-dev at openjdk.java.net
>> Subject: Re: Inferring that what exceptions are thrown from a lambda
>>
>> It is just a matter of cost vs. benefit, is it worth defining the extra generic parameter
>> for the benefit? I have found it not worth the trouble.
>>
>> Sent from my iPad
>>
>> On 07/09/2013, at 10:01 AM, Stuart Marks <stuart.marks at oracle.com> wrote:
>>
>>> Not sure what you mean by "quickly end up at Exception." Depends on what's in the
>> lambda. Certain things, like Future.get() or ObjectInputStream.writeObject() are
>> declared to throw two checked exceptions whose common supertype is Exception. But
>> there also seem to be many cases where code throws a single checked exception, or
>> none at all, and for these cases callers benefit by having to handle only the right
>> checked exception or none at all.
>>>
>>> s'marks
>>>
>>> On 9/5/13 7:47 PM, Howard Lovatt wrote:
>>>> Sure, but as your example shows you quickly end up at Exception and
>>>> therefore I start there! The enclosing method can catch the more
>>>> specific exceptions, if you know what they are, and rethrow the specific
>>>> exceptions so that the enclosing method doesn't have to throw Exception
>>>> but can throw the specific exceptions.
>>>>
>>>> -- Howard.
>>>>
>>>>
>>>> On 6 September 2013 12:22, Stuart Marks <stuart.marks at oracle.com
>>>> <mailto: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.
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> -- Howard.
>
>
> Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Dr. Wolfram Jost, Arnd Zinnhardt; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com
>
>
More information about the lambda-dev
mailing list