JDK8之前

在JDK8之前,如果我们要创建一个Thread示例,经常会这样写:

  1. public class FunctionInterfaceTest {
  2. public static void main(String[] args) {
  3. Thread thread = new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. System.out.println(Thread.currentThread().getName());
  7. }
  8. });
  9. thread.start();
  10. }
  11. }

因为Thread要接受一个Runnable接口的实例作为参数,所以我们需要给定它这个Runnable。这实际上是匿名内部类的写法,new Runnable这段代码就是创建了一个匿名内部类。
我们可以思考一下,在这个例子中,实际上我们最需要和最关心的其实是Runnable的run方法,因为是它给定了代码要执行的逻辑。在之前关于匿名内部类的讲解中,我们也说过,匿名内部类一般就会用来重写接口或者抽象类中的方法。
所以为了重写一个run方法,我们不得不创建一个内部类。这就产生了大量的冗余和样板代码,这些冗余样板代码甚至都要掩盖了我们代码的真实意图。有没有一种方式,我们可以直接就给定Thread类要执行的代码逻辑而无需产生大量的其他代码?使用JDK8提供的lambda表达式就可以。

JDK8

在JDK8中,上面的代码可以这样实现:

  1. public static void main(String[] args) {
  2. Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getName()));
  3. thread.start();
  4. }

看到了没,没有创建匿名内部类的代码,甚至没有重写run方法的声明,直接就给出了run方法中的逻辑(注意这里只是源文件中没有给出,实际上编译器还是会做一些动作)。这样相比上面的写法,是不是简单了很多。
我们简单看下这个表达式:

  1. () -> System.out.println(Thread.currentThread().getName();

这就是一个最简单的lambda表达式。前面一个括号,紧接着一个 -> 然后是run方法中的代码。这里简单解释一下,最前面的括号是给定参数的,即run方法的参数,因为run方法没有参数,所以这里就是一个空括号,然后 ->是lambda的语法,后面的代码就是run的方法体。
看到这里,我们一定会有几个疑问:

  1. 为什么这里没有指定run方法?如果Runnable还有另外一个方法怎么办?
  2. 如果有一个或者多个参数怎么办?
  3. 参数的类型需要指定吗?
  4. 方法如果有返回值怎么办?
  5. 如果方法体不止一行怎么办?

我们后面会一一说明这几点疑问。