首页 > 解决方案 > 如何在需要 Runnable Instance 的地方接受方法引用运算符?

问题描述

我最近遇到了下面的示例代码,其中方法引用运算符用于引用方法调用。有 2 个问题我正在寻找答案 1. 调用它的执行方法需要 Runnable 类。此代码编译文件并且没有给出错误为什么(App 类不是 Runnable)?2.如果我替换 executorService.execute(app::someMethod); 与 executorService.execute(app.someMethod()); 它给出了编译错误,为什么?

public class Temp {

private static final Logger LOGGER = LoggerFactory.getLogger(Temp.class);

/**
 * @param args the command line arguments - not used
 */`enter code here`
public static void main(String... args) {
    final App app = new App();
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 3; i++) {
        executorService.execute(app::someMethod);
    }
    executorService.shutdown();
    try {
        executorService.awaitTermination(10, TimeUnit.SECONDS);
    } catch (InterruptedException ie) {
        LOGGER.error("ERROR: Waiting on executor service shutdown!");
    }
}

}
class App {
     public void someMethod() {
           // Some logic
     }
}

标签: javamultithreadingjava-8method-reference

解决方案


ExecutorService.execute需要一个类型的参数Runnable

首先回答你的最后一个问题......App.someMethod()是一种void方法(即它不返回任何东西)。由于app.someMethod()的返回类型是void,并且由于void无法将类型分配给 type 的变量或方法参数Runnable,因此会出现编译错误。

现在,至于你的第一个问题......Runnable接口是一个功能接口,因为它声明了一个抽象方法(SAM):

@FunctionalInterface
public interface Runnable {

    void run();
}

这里的 SAM 是void run(),它不接收任何参数并且是一种void方法。

现在,方法引用app::someMethod目标是类的void someMethod()方法App,其签名接口的run方法之一匹配Runnable(通过匹配我的意思是两个方法的返回类型都是void,并且它们都没有接收任何参数)。

因此,当您将app::someMethod方法引用作为参数传递给executorService.execute方法时,编译器会安全地其转换为Runnable实例。


编辑:正如用户@MC Emperor 在评论中强调的那样,类的someMethod方法可能会返回一些东西(即它不一定是方法)。在这种情况下,如规范所述(请参阅JLS § 15.27.3,感谢您的链接!),返回值将被简单地丢弃。Appvoid

这是因为在 Java 中,方法返回的值可以被丢弃,并且方法引用(以及 lambda 表达式)尊重这种行为。


推荐阅读