Java Lambda 表达式和对泛型方法的方法引用
Java Lambda Expressions and Method References to Generic Methods
我有一个功能界面
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
@FunctionalInterface
public interface SubmitterCompletable extends Submitter {
@Override
<T> CompletableFuture<T> submit(Callable<T> task);
}
和两个函数
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) {
// ...
}
}
并且我想使用 lambda 表达式或方法引用从这些函数创建 SubmitterCompletable
。第一个通过使用方法引用工作正常。
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync;
然而,对于第二个,我必须使用 lambda 表达式来传递 Executor
,但它不起作用。
Executor executor = /* ... */;
SubmitterCompletable submitterCompletable = c -> CompletableFutureUtils.runAsync(c, executor);
// Illegal lambda expression: Method submit of type SubmitterCompletable is generic
我的问题是在这种情况下是否有有效的 lambda 表达式,或者在这种情况下我是否必须创建一个匿名 class?
有一个有效的lambda表达式,但是,你需要将SubmitterCompletable
中的泛型类型从方法移动到class级别,只要泛型类型无法构造lambda表达式在方法中定义:
@FunctionalInterface
public interface SubmitterCompletable<T> extends Submitter { // notice the <T>
@Override
CompletableFuture<T> submit(Callable<T> task); // reuses the generic type
}
Executor executor = /* ... */;
SubmitterCompletable<Whatever> submitterCompletable = c -> runAsync(c, executor);
这里的问题是“仅当功能接口中的方法具有 NO 类型参数时,lambda 表达式才能用于功能接口”。 (JLS11, 15.27.3 Type of a Lambda Expression) 但有一个例外 - 一致 方法引用并非如此。
这就是为什么它在您的第一个示例中起作用而在第二个示例中不起作用的原因:
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync; (OK)
SubmitterCompletable submitterCompletable = c -> <anything> (NOT OK)
我能想到的选项不多可以实现您想要的:
实现接口(就地使用您提到的匿名 class 或作为独立的 class)。
在你的 CompletableFutureUtils
中使用一个中间助手 class,它将保持对执行程序的引用并公开一个方法 congruent您的提交者的功能方法,它将调用委托给底层 runAsync(Callable<U> callable, Executor executor)
util 的方法。
示例代码:
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);
}
}
}
用法示例:
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync;
SubmitterCompletable submitterWithExecutor = CompletableFutureUtils.using(executor)::runAsync;
我有一个功能界面
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
@FunctionalInterface
public interface SubmitterCompletable extends Submitter {
@Override
<T> CompletableFuture<T> submit(Callable<T> task);
}
和两个函数
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) {
// ...
}
}
并且我想使用 lambda 表达式或方法引用从这些函数创建 SubmitterCompletable
。第一个通过使用方法引用工作正常。
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync;
然而,对于第二个,我必须使用 lambda 表达式来传递 Executor
,但它不起作用。
Executor executor = /* ... */;
SubmitterCompletable submitterCompletable = c -> CompletableFutureUtils.runAsync(c, executor);
// Illegal lambda expression: Method submit of type SubmitterCompletable is generic
我的问题是在这种情况下是否有有效的 lambda 表达式,或者在这种情况下我是否必须创建一个匿名 class?
有一个有效的lambda表达式,但是,你需要将SubmitterCompletable
中的泛型类型从方法移动到class级别,只要泛型类型无法构造lambda表达式在方法中定义:
@FunctionalInterface
public interface SubmitterCompletable<T> extends Submitter { // notice the <T>
@Override
CompletableFuture<T> submit(Callable<T> task); // reuses the generic type
}
Executor executor = /* ... */;
SubmitterCompletable<Whatever> submitterCompletable = c -> runAsync(c, executor);
这里的问题是“仅当功能接口中的方法具有 NO 类型参数时,lambda 表达式才能用于功能接口”。 (JLS11, 15.27.3 Type of a Lambda Expression) 但有一个例外 - 一致 方法引用并非如此。
这就是为什么它在您的第一个示例中起作用而在第二个示例中不起作用的原因:
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync; (OK)
SubmitterCompletable submitterCompletable = c -> <anything> (NOT OK)
我能想到的选项不多可以实现您想要的:
实现接口(就地使用您提到的匿名 class 或作为独立的 class)。
在你的
CompletableFutureUtils
中使用一个中间助手 class,它将保持对执行程序的引用并公开一个方法 congruent您的提交者的功能方法,它将调用委托给底层runAsync(Callable<U> callable, Executor executor)
util 的方法。
示例代码:
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);
}
}
}
用法示例:
SubmitterCompletable submitterCompletable = CompletableFutureUtils::runAsync;
SubmitterCompletable submitterWithExecutor = CompletableFutureUtils.using(executor)::runAsync;