Lambda:使用Runnable实例启动的可调用变量

时间:2017-07-25 10:11:52

标签: java lambda java-8

刚刚发现了一种奇怪而有趣的Lambda行为。

让我们拥有以下课程:

private class Task implements Runnable {
    @Override
    public void run() {
       // something to process
    }
}

以下语句正在编译并运行:

Callable task = Task::new;

有人可以解释为什么这是可能的吗?

修改

根据以下答案,请查看以下声明:

1

ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(Task::new);

2

ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(new Task());

乍一看,似乎是一样的,但实际上是完全不同的事情。

这里发生的正是上述情况。

原因是ExecutorService有两种方法:

submit(Runnable); submit(Callable);

因此,使用来自1的代码。执行者将在其内部线程上处理以下内容:

new Task()

来自2.的版本实际上将调用submit(Runnable)方法,并且将执行Task.run中的代码。

结论:小心使用Lambdas :)

2 个答案:

答案 0 :(得分:4)

Callable 使用Runnable实例进行初始化,它使用对生成 a的Task构造函数的方法引用进行初始化执行时Runnable

换句话说,如果执行Callable,它将返回一个新的Task对象,其中尚未尚未运行。 Task实现Runnable实际上与此完全无关。

如果您不使用原始类型,这将更加清晰。可以将Task::new分配给Callable<Task>,因为它不需要参数并返回任务。

答案 1 :(得分:2)

要实现Callable<V>接口,必须使用签名V call()实现一个方法。

因此,您可以使用任何不带任何方法的方法引用来实现此接口,并返回一些引用类型,其中包括构造函数方法引用,例如Task::new

实际上,任何具有无参数构造函数的类都可以这样使用:

Callable<SomeClass> callable = SomeClass::new;