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 and Errors.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);
            }
        };