Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I re-throw an exception in a lambda block as from the outer block?

With following code,

void key(Key) throws SomeCheckedException {
}

void supplier(Supplier<Key> s) throws SomeCheckedException {
    ofNullable(s).ifPresent(s -> {                   //    |
        try {                                        //    |
            key(s.get());                            //    |
        } catch (final SomeCheckedException sce) {   //    |
            // sce is coming from key() method       //    |
            // How can I throw sce for outer method? //  --/
        }
    });
}

How can I throw sce as if the method(supplier) method is throwing it?

Please note that above code is just an example. I need the key(s.get()) to be inside a lambda expression.

void supplier(Supplier<Key> s) throws SomeCheckException {
    key(s.get());
}
like image 206
Jin Kwon Avatar asked Jan 12 '15 05:01

Jin Kwon


People also ask

Can you throw any exception inside a lambda expression's body?

A lambda expression body can't throw any exceptions that haven't specified in a functional interface. If the lambda expression can throw an exception then the "throws" clause of a functional interface must declare the same exception or one of its subtype.

How do you handle exceptions in lambda expression?

The most straightforward way would be to use a try-catch block, wrap the checked exception into an unchecked exception and rethrow it: List<Integer> integers = Arrays. asList(3, 9, 7, 0, 10, 20); integers. forEach(i -> { try { writeToFile(i); } catch (IOException e) { throw new RuntimeException(e); } });

Can you throw exception in block Java?

The caller has to handle the exception using a try-catch block or propagate the exception. We can throw either checked or unchecked exceptions. The throws keyword allows the compiler to help you write code that handles this type of error, but it does not prevent the abnormal termination of the program.

Is there any way of throwing a checked exception from a method that does not have a throws clause?

Without using throws When an exception is cached in a catch block, you can re-throw it using the throw keyword (which is used to throw the exception objects). If you re-throw the exception, just like in the case of throws clause this exception now, will be generated at in the method that calls the current one.


2 Answers

You can't. Supplier#get() does not declare to throw any (checked) exceptions. Remember that a lambda expression simply creates an instance, it doesn't actually invoke the target functional interface method.

If you want to, you can wrap the checked exception in an unchecked exception and throw that.

like image 183
Sotirios Delimanolis Avatar answered Nov 10 '22 00:11

Sotirios Delimanolis


If you want to process checked exceptions in a safe manner you need a helper method which provides the facility of wrapping the exception into a sub-type of RuntimeException. Here is such a helper function which uses Generic’s type safety to ensure that only declared exceptions will be re-thrown (unless you use an unsafe operation):

public static <E extends Throwable> void attempt(
    Consumer<Function<E,RuntimeException>> action) throws E {

    final class CarryException extends RuntimeException {
        final E carried;
        CarryException(E cause) {
            super(cause);
            carried=cause;
        }
    }

    try { action.accept( CarryException::new ); }
    catch(CarryException ex) { throw ex.carried; }
}

It supports an arbitrary action which will receive a function which does the temporary wrapping of the checked exception type to the RuntimeException. This wrapping will be transparent, the method attempt will either complete normally or throw the original checked exception E (or an unrelated unchecked exception if one occurs).

So you can use it like this:

public static void processIterm(Supplier<Key> s)
    throws SomeCheckedException  {

    attempt( (Function<SomeCheckedException, RuntimeException> thrower) ->
        Optional.ofNullable(s).ifPresent(nonNull -> {
            try { key(nonNull.get()); } // assuming key may throw SomeCheckedException
            catch(SomeCheckedException  e) { throw thrower.apply(e); }
        }));
}

Due to the nested operations the compiler is unable to infer the exception type automatically. The code above use an explicit declaration of the thrower parameter type. Alternatively you can use a type invocation of the helper method like

ContainingClass.<SomeCheckedException>attempt( thrower ->
    Optional.ofNullable(s).ifPresent(nonNull -> {
        try { key(nonNull.get()); }
        catch(SomeCheckedException  e) { throw thrower.apply(e); }
    }));
like image 28
Holger Avatar answered Nov 09 '22 23:11

Holger