简体   繁体   English

Java Lambda 表达式和方法对通用方法的引用

[英]Java Lambda Expressions and Method References to Generic Methods

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.我想使用 lambda 表达式或方法引用从这些函数创建SubmitterCompletable 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.但是,对于第二个,我必须使用 lambda 表达式来传递Executor并且它不起作用。

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?我的问题是在这种情况下是否存在有效的 lambda 表达式,还是在这种情况下我必须创建一个匿名 class ?

There is a valid lambda expression, however, you need to move the generic type in SubmitterCompletable from the method to the class level as long as lambda expression cannot be constructed if the generic type is defined at the method:有一个有效的 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);

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".那里的问题是“仅当功能接口中的方法没有类型参数时, lambda表达式才能用于功能接口”。 (JLS11, 15.27.3 Type of a Lambda Expression ) with one exception - this is not the case for congruent method references. (JLS11, 15.27.3 Type of a Lambda Expression )有一个例外 - 这不是全等方法引用的情况。

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:我想不到很多选择来实现你想要的:

  1. Implement the interface (either in-place using an anonymous class as you've mentioned or as a standalone class).实现接口(如您所提到的,使用匿名 class 就地或作为独立类)。

  2. 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.CompletableFutureUtils中使用中间帮助器 class ,它将保留对执行程序的引用并公开与提交者的功能方法一致的方法,该方法将调用委托给底层的runAsync(Callable<U> callable, Executor executor) util的方法。

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM