I have a functional interface
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
@FunctionalInterface
public interface SubmitterCompletable extends Submitter {
@Override
<T> CompletableFuture<T> submit(Callable<T> task);
}
and two functions
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
public final class CompletableFutureUtils {
public static <U> CompletableFuture<U> runAsync(Callable<U> callable) {
// ...
}
public static <U> CompletableFuture<U> runAsync(Callable<U> callable, Executor executor) {
// ...
}
}
and I want to create SubmitterCompletable
s from these functions using lambda expressions or method references. The first one works fine by using method references.
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync;
For the second one, however, I have to use a lambda expression to pass an Executor
and it doesn't work.
Executor executor = /* ... */;
SubmitterCompletable submitterCompletable = c -> CompletableFutureUtils.runAsync(c, executor);
// Illegal lambda expression: Method submit of type SubmitterCompletable is generic
My question is whether there is a valid lambda expression for this case, or do I have to create an anonymous class in this case?
The issue there is that "a lambda expression can be used for a functional interface only if the method in the functional interface has NO type parameters". (JLS11, 15.27.3 Type of a Lambda Expression) with one exception - this is not the case for congruent method references.
That is why it works in your first example and doesn't in the second:
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync; (OK)
SubmitterCompletable submitterCompletable = c -> <anything> (NOT OK)
There aren't many options out there I could think of to achieve what you want:
Implement the interface (either in-place using an anonymous class as you've mentioned or as a standalone class).
Use an intermediate helper class inside your CompletableFutureUtils
that would keep a ref to the executor and expose a method congruent with your Submitter's functional method which will delegate the call to the underlying runAsync(Callable<U> callable, Executor executor)
util's method.
Example code:
public final static class CompletableFutureUtils {
public static <U> CompletableFuture<U> runAsync(Callable<U> callable) {
...
}
public static <U> CompletableFuture<U> runAsync(Callable<U> callable, Executor executor) {
...
}
public static ExecutorRunnerProxy using(Executor executor) {
return new ExecutorRunnerProxy(executor);
}
public static final class ExecutorRunnerProxy {
private final Executor executor;
private ExecutorRunnerProxy(Executor executor) {
this.executor = executor;
}
public <T> CompletableFuture<T> runAsync(Callable<T> task) {
return CompletableFutureUtils.runAsync(task, executor);
}
}
}
Example usage:
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync;
SubmitterCompletable submitterWithExecutor = CompletableFutureUtils.using(executor)::runAsync;