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());
}
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.
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); } });
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.
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.
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.
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); }
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With