Java 8 Lambda function that throws exception?
This is not specific to Java 8. You are trying to compile something equivalent to:
interface I {
void m();
}
class C implements I {
public void m() throws Exception {} //can't compile
}
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
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)));
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); } };