Checked exceptions within Block<T>

Zhong Yu zhong.j.yu at gmail.com
Sat Jan 12 08:03:43 PST 2013


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