Java 8 Lambda function that throws exception?
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:
@FunctionalInterfacepublic 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); } };
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
):
@FunctionalInterfacepublic 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)));
I think Durian's Errors
class combines many of the pros of the various suggestions above.
- Wrap a throwing function to a standard Java 8 functional interface.
- Easily specify various policies for handling errors
- When wrapping a method that returns a value, there is an important distinction between specifying a default value or rethrowing a RuntimeException.
- Throwing versions of Java 8's functional interfaces
- Similar to fge's answer
- Standard interfaces for throwing specific exceptions
- Which addresses Zoltán's concern
To include Durian in your project, you can either:
- grab it from jcenter or maven central at
com.diffplug.durian:durian:3.3.0
- or just copy paste just two small classes into your code:
Throwing.java
andErrors.java