2.1 第一个Lambda表达式

Swing是一个与平台无关的Java类库,用来编写图形用户界面(GUI)。该类库有一个常见用法:为了响应用户操作,需要注册一个事件监听器。用户一输入,监听器就会执行一些操作(见例2-1)。

例2-1 使用匿名内部类将行为和按钮单击进行关联

  1. button.addActionListener(new ActionListener() {
  2. public void actionPerformed(ActionEvent event) {
  3. System.out.println("button clicked");
  4. }
  5. });

在这个例子中,我们创建了一个新对象,它实现了ActionListener接口。这个接口只有一个方法actionPerformed,当用户点击屏幕上的按钮时,button就会调用这个方法。匿名内部类实现了该方法。在例2-1中该方法所执行的只是输出一条信息,表明按钮已被点击。

2.1 第一个Lambda表达式 - 图1这实际上是一个代码即数据的例子——我们给按钮传递了一个代表某种行为的对象。

设计匿名内部类的目的,就是为了方便Java程序员将代码作为数据传递。不过,匿名内部类还是不够简便。为了调用一行重要的逻辑代码,不得不加上4行冗繁的样板代码。若把样板代码用其他颜色区分开来,就可一目了然:

  1. button.addActionListener(new ActionListener() {
  2. public void actionPerformed(ActionEvent event) {
  3. System.out.println("button clicked");
  4. }
  5. });

尽管如此,样板代码并不是唯一的问题:这些代码还相当难读,因为它没有清楚地表达程序员的意图。我们不想传入对象,只想传入行为。在Java 8中,上述代码可以写成一个Lambda表达式,如例2-2所示。

例2-2 使用Lambda表达式将行为和按钮单击进行关联

  1. button.addActionListener(event -> System.out.println("button clicked"));

和传入一个实现某接口的对象不同,我们传入了一段代码块——一个没有名字的函数。event是参数名,和上面匿名内部类示例中的是同一个参数。->将参数和Lambda表达式的主体分开,而主体是用户点击按钮时会运行的一些代码。

和使用匿名内部类的另一处不同在于声明event参数的方式。使用匿名内部类时需要显式地声明参数类型ActionEvent event,而在Lambda表达式中无需指定类型,程序依然可以编译。这是因为javac根据程序的上下文(addActionListener方法的签名)在后台推断出了参数event的类型。这意味着如果参数类型不言而明,则无需显式指定。稍后会介绍类型推断的更多细节,现在先来看看编写Lambda表达式的各种方式。

2.1 第一个Lambda表达式 - 图2尽管与之前相比,Lambda表达式中的参数需要的样板代码很少,但是Java 8仍然是一种静态类型语言。为了增加可读性并迁就我们的习惯,声明参数时也可以包括类型信息,而且有时编译器不一定能根据上下文推断出参数的类型!