在预期可运行实例的情况下,如何接受方法引用运算符?



我最近遇到了下面的示例代码,其中使用方法引用运算符来引用方法调用。我正在寻找2个问题的答案 1. 执行方法,其中调用它需要 Runnable 类。此代码编译文件并且没有给出错误,为什么(应用程序类不可运行)? 2. 如果我替换执行器服务.执行(app::someMethod);with 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
}
}

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

先回答你的最后一个问题...App.someMethod()是一种void方法(即它不返回任何内容)。由于app.someMethod()的返回类型是void,并且void类型不能分配给类型为Runnable的变量或方法参数,因此你会得到一个编译错误。

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

@FunctionalInterface
public interface Runnable {
void run();
}

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

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

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


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

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

1)是的,App 类不可运行,但在您的示例中,它不是您传递给执行方法的 App 对象,而是您在那里进行方法引用。

2) app::someMethod 是对特定对象的实例方法的引用。app.someMethod() 只是对 someMethod() 的调用,预计它会返回一个实现 Runnable 接口的对象。不是,这就是您出现错误的原因。

最新更新