Checked exceptions within Block<T>

Brian Goetz brian.goetz at oracle.com
Sat Jan 12 09:49:45 PST 2013


Yes, you'd have to provide your own exceptional SAMs.  But then lambda 
conversion would work fine with them.

The EG discussed additional language and library support for this 
problem, and in the end felt that this was a bad cost/benefit tradeoff.

Library-based solutions cause a 2x explosion in SAM types (exceptional 
vs not), which interact badly with existing combinatorial explosions for 
primitive specialization.

The available language-based solutions were losers from a 
complexity/value tradeoff.  Though there are some alternative solutions 
we are going to continue to explore -- though clearly not for 8 and 
probably not for 9 either.

In the meantime, you have the tools to do what you want.  I get that you 
prefer we provide that last mile for you (and, secondarily, your request 
is really a thinly-veiled request for "why don't you just give up on 
checked exceptions already"), but I think the current state lets you get 
your job done.

On 1/12/2013 12:35 PM, Zhong Yu wrote:
> You are probably mistaken here, since b.accept(e) does not throw
> checked exceptions.
>
> If you what you really meant was a solution like Peter Levart's,
> should it (BlockEx) be included in standard lib? Since it might be
> useful to a wide audience.
>
> Zhong Yu
>
> On Sat, Jan 12, 2013 at 11:21 AM, Brian Goetz <brian.goetz at oracle.com> wrote:
>> Or you could write your own trivial combinator:
>>
>> static<T> Block<T> exceptionWrappingBlock(Block<T> b) {
>>      return e -> {
>>          try { b.accept(e); }
>>          catch (Exception e) { throw new RTE(e); }
>>      };
>> }
>>
>> You can write it once, in less that the time it took to write your original
>> e-mail.  And similarly once for each kind of SAM you use.
>>
>> I'd rather we look at this as "glass 99% full" rather than the alternative.
>> Not all problems require new language features as solutions.  (Not to
>> mention that new language features always causes new problems.)
>>
>>
>>
>> On 1/12/2013 11:03 AM, Zhong Yu wrote:
>>>
>>> I too have this problem, since we have lots of code throwing checked
>>> exceptions, it's a challenge to wrap them in functional interfaces
>>> that do not throw.
>>>
>>> If the solution is to smuggle checked exception as unchecked, JDK
>>> should provide a standard class for that specific purpose, or
>>> everybody will be forced to invent their own.
>>>
>>> A better solution is probably having varying exceptions
>>>
>>>       interface Block<T, E extends Throwable>
>>>           void apply(T input) throws E;
>>>
>>>       <T,E extends Throwable> void forEach(Block<T,E> block) throws E
>>>
>>> this is very ugly though; I'd dream the language could make it simpler
>>> like
>>>
>>>       interface Block<T>
>>>           void apply(T input) throws ?;
>>>           // abstract method; throws E; add E to interface.
>>>
>>>       <T> void forEach(Block<T> block) throws ? { ... }
>>>       // non-abstract method; throws E; add E to method.
>>>
>>>
>>> Zhong Yu
>>>
>>> On Fri, Jan 11, 2013 at 10:12 PM, Michael Hixson
>>> <michael.hixson at gmail.com> wrote:
>>>>
>>>> This is a bit of feedback for the lambda snapshots.  It's not really
>>>> suggesting any changes or reporting bugs, but rather describing
>>>> difficulties I had.  Hopefully this is the right mailing list for this
>>>> sort of thing.
>>>>
>>>> --------------------------------
>>>>
>>>> An issue that came up repeatedly was that I wanted refactor code like
>>>> this:
>>>>
>>>>     for (Value value : values) {
>>>>       ...
>>>>     }
>>>>
>>>> Into this:
>>>>
>>>>     values.forEach(value -> {
>>>>       ...
>>>>     });
>>>>
>>>> But I couldn't because the "..." could throw a checked exception.  I
>>>> worked around this in two ways:
>>>>
>>>>     (a) Don't refactor the code.
>>>>     (b) Change whatever is throwing the checked exception to throw a
>>>> runtime exception instead.
>>>>
>>>> Option (a) was not so bad if my "values" object was an Iterable.  It
>>>> was worse when my values were a Map, a Stream, or an Optional.  To
>>>> compare:
>>>>
>>>>     for (Map.Entry<Key, Value> entry : values.entrySet()) {
>>>>       Key key = entry.getKey();
>>>>       Value value = entry.getValue();
>>>>       ...
>>>>     }
>>>>
>>>>     values.forEach((key, value) -> {
>>>>       ...
>>>>     });
>>>>
>>>>     for (Iterator iterator =
>>>> values.stream().filter(predicate).map(function).iterator();
>>>>          iterator.hasNext();) {
>>>>       Value value = iterator.next();
>>>>       ...
>>>>     }
>>>>
>>>>     values.stream().filter(predicate).map(function).forEach(value -> {
>>>>       ...
>>>>     });
>>>>
>>>>     Optional<Value> optionalValue = somethingThatGivesAnOptional();
>>>>     if (optionalValue.isPresent()) {
>>>>       Value value = optionalValue.get();
>>>>       ...
>>>>     }
>>>>
>>>>     somethingThatGivesAnOptional().ifPresent(value -> {
>>>>       ...
>>>>     });
>>>>
>>>> In one case (really several cases that relied on the same utility)
>>>> that was enough to drive me to option (b).
>>>>
>>>> Option (b) allowed me to use the new lambda goodness but made me
>>>> slightly uncomfortable.  The utility in question could write values in
>>>> CSV format to an Appendable.  Since Appendable can throw IOExceptions,
>>>> I initially had the utility methods throw IOException.  To make it
>>>> lambda-friendly I changed all its methods to look like this:
>>>>
>>>>     try {
>>>>       ...
>>>>     } catch (IOException e) {
>>>>       throw new UncheckedIOException(e);
>>>>     }
>>>>
>>>> This was fine because I wasn't catching any IOExceptions that occurred
>>>> in the first place (this code was running in response to a web
>>>> request, and if an exception occurred the framework would handle it
>>>> and show an error page).  But I felt that it made my CSV utility a
>>>> little more "dangerous" for general use.  This is all sort of
>>>> hand-wavey, but I don't like that the utility now potentially throws
>>>> runtime exceptions when there's not a programmer error and when there
>>>> might be a reasonable way to recover.  Plus it is additional code in
>>>> my utility class, and good thing it is my class and not someone
>>>> else's.
>>>>
>>>> What I really wanted to do was leave in the checked exceptions *and*
>>>> use the lambda forEach/ifPresent forms.
>>>>
>>>> -Michael
>>>>
>>>
>>


More information about the lambda-dev mailing list