Java 8 Lambda function that throws exception?
Solution 1:
You'll need to do one of the following.
-
If it's your code, then define your own functional interface that declares the checked exception:
@FunctionalInterface public interface CheckedFunction<T, R> { R apply(T t) throws IOException; }
and use it:
void foo (CheckedFunction f) { ... }
-
Otherwise, wrap
Integer myMethod(String s)
in a method that doesn't declare a checked exception:public Integer myWrappedMethod(String s) { try { return myMethod(s); } catch(IOException e) { throw new UncheckedIOException(e); } }
and then:
Function<String, Integer> f = (String t) -> myWrappedMethod(t);
or:
Function<String, Integer> f = (String t) -> { try { return myMethod(t); } catch(IOException e) { throw new UncheckedIOException(e); } };
Solution 2:
You can actually extend Consumer
(and Function
etc.) with a new interface that handles exceptions -- using Java 8's default methods!
Consider this interface (extends Consumer
):
@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {
@Override
default void accept(final T elem) {
try {
acceptThrows(elem);
} catch (final Exception e) {
// Implement your own exception handling logic here..
// For example:
System.out.println("handling an exception...");
// Or ...
throw new RuntimeException(e);
}
}
void acceptThrows(T elem) throws Exception;
}
Then, for example, if you have a list:
final List<String> list = Arrays.asList("A", "B", "C");
If you want to consume it (eg. with forEach
) with some code that throws exceptions, you would traditionally have set up a try/catch block:
final Consumer<String> consumer = aps -> {
try {
// maybe some other code here...
throw new Exception("asdas");
} catch (final Exception ex) {
System.out.println("handling an exception...");
}
};
list.forEach(consumer);
But with this new interface, you can instantiate it with a lambda expression and the compiler will not complain:
final ThrowingConsumer<String> throwingConsumer = aps -> {
// maybe some other code here...
throw new Exception("asdas");
};
list.forEach(throwingConsumer);
Or even just cast it to be more succinct!:
list.forEach((ThrowingConsumer<String>) aps -> {
// maybe some other code here...
throw new Exception("asda");
});
Update: Looks like there's a very nice utility library part of Durian called Errors which can be used to solve this problem with a lot more flexibility. For example, in my implementation above I've explicitly defined the error handling policy (System.out...
or throw RuntimeException
), whereas Durian's Errors allow you to apply a policy on the fly via a large suite of utility methods. Thanks for sharing it, @NedTwigg!.
Sample usage:
list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));