为什么可以在Thread类中使用Lambda表达式?

时间:2014-07-20 03:21:00

标签: lambda java-8

我正在学习Lambda表达式,我知道可以在Runnable功能界面和Thread类中使用它们。

我试图创建自己的:

package tests;

public interface Blabla
{
    public void doStuff();
}

编译这个简单的测试:

Blabla bla = () -> System.out.println("Lol");

然后我尝试创建一个类似Thread

的类
package tests;

public class Dodo implements Blabla
{
    public void doStuff()
    {
        // TODO Auto-generated method stub

    }
}

这不会编译:

 Dodo dodo = () -> System.out.println("LoL");

我无法解释如何创建一个允许使用lambda表达式的类。

如何在不作为接口的情况下允许使用Lambda表达式?

2 个答案:

答案 0 :(得分:5)

  

如何在不作为接口的情况下允许使用Lambda表达式?

我认为你对Thread类如何使用lambdas感到有些困惑。 lambda不会转换为Thread类本身的实例;相反,lambdas被转换为Runnable功能接口的子类的实例,然后传递给已经overloaded to take a Runnable object的Thread构造函数。

因此,当你做这样的事情时:

new Thread(() -> System.out.println("Lol")).start();

lambda未转换为您正在创建的Thread对象。相反,它被转换为传递给Thread构造函数的Runnable对象。

如果将lambda与Thread对象分开,则更清楚:

Runnable temp = () -> System.out.println("Lol");

new Thread(temp).start();

考虑一个Thread 执行一个函数而不是 一个函数可能会有所帮助。您必须保持Thread执行的功能与Thread本身不同。

请注意,lambdas转换为对象的方式是一个实现细节,在将来的Java版本中可能会发生变化(Java 1.8.0_11是编写本答案时的最新版本)。请参阅下面的Stuart Marks的评论。


  

我无法解释如何创建一个允许使用lambda表达式的类。

如果我正确理解你,你希望写一个类,这样你就可以根据该类创建一个lambda。

不幸的是,你做不到。请参阅Java语言规范,第15.27节:

  

评估lambda表达式会产生一个功能接口的实例(§9.8)。

这里的关键点是lambda是接口的一个实例。因此,您不能使用lambda直接对类进行子类化。有关这方面的理由可以在Brian Goetz的this电子邮件中找到JDK lambda-dev邮件列表(感谢Stuart Marks指出这一点!);简而言之,这个决定至少部分地做出了,所以Java可以继续朝着新的方向发展。

可以做的是编写一个类,其构造函数和/或方法将一个或多个函数接口作为参数,让你通过传递实例来使用lambdas类周围的功能接口(如Thread类)。目前(据我所知),这几乎和它一样好。

答案 1 :(得分:0)

lambda表达式只是编写匿名类的简短形式,通过使用lambda表达式,我们可以在任何我们想要的地方声明方法,而不需要任何名称。

编写匿名类对象的唯一目的是覆盖其方法并提供我们自己的功能,但对于该单个方法,我们总是需要声明该类。使用lambda表达式,我们可以消除匿名类的声明,我们可以简单地提供方法的定义。

例如,我们使用下面的代码来创建一个线程

Runnable runnable = new Runnable() {
  @Override
  public void run() {
  System.out.println("Running thread using anonymous class");
  }
};
Thread t = new Thread(runnable);

但是使用lambda表达式我们可以很容易地说

Runnable runnable = () -> System.out.println("Running thread using lambda expression");
Thread t = new Thread(runnable);

或者

Thread t = new Thread(() -> System.out.println("Running thread using lambda expression"));

因此,通过编写Runnable runnable = () -> System.out.println("Running thread using lambda expression");,我们告诉Java创建一个Runnable类型的匿名对象,并提供run()方法的主体。

Lambda表达式仅适用于functional interfaces(一个只有一个方法的接口),因为我们正在为方法提供实体。因此,如果一个接口有多个方法,并且允许我们在其上创建一个lambda,那么编译器将如何识别这个方法体所属的方法。

Lambda Expression和Anonymous类之间的差异如下

  • 匿名类对象在编译后创建一个单独的类文件,这会在编译后增加jar的大小,而Lambda表达式变为invokedynamic,这是动态语言实现。
  • 我们可以使用this关键字来表示lambda表达式中的当前类,而在匿名类的情况下,此关键字表示该特定的匿名类。
  • 在Lambda表达式的情况下,我们只需要提供函数体,而在匿名类的情况下,我们需要编写冗余类定义。

您可以在Java Lambda Expression Explained with Example上阅读更多内容。