- 创建接口实现类。
- 创建匿名类。
可以使用 lambda 表达式实现功能接口,无需创建类或匿名类。Lambda 表达式只能用于单一方法声明接口。
Lambda 表达式旨在支持多核处理器架构,这种架构依赖于提供并行机制的软件,而该机制可以提高性能、减少完成时间。
Lambda 表达式具有以下优点:
- 简明的语法
- 方法引用和构造函数引用
- 相比于匿名类,减少了运行时开销
Lambda 表达式的语法
Lambda 表达式的语法如下所示。
(formal parameter list) ->{ expression or statements }
参数列表是一个逗号分隔的形式参数列表,这些参数与功能接口中单一方法的形式参数相对应。指定参数类型是可选项;如果未指定参数类型,将从上下文推断。
参数列表必须用括号括起来,但当指定的单一参数不带参数类型时除外,指定单一形式参数时可以不带括号。如果功能接口方法不指定任何形式参数,则必须指定空括号。
参数列表后面是 -> 运算符,然后是 lambda 主体,即单一表达式或语句块。Lambda 主体的结果必须是下列值之一:
- void,如果功能接口方法的结果是 void
- Java 类型、基元类型或引用类型,与功能接口方法的返回类型相同
Lambda 主体根据以下选项之一返回结果:
- 如果 lambda 主体是单一表达式,则返回表达式的值。
- 如果该方法具有返回类型,且 lambda 主体不是单一表达式,则 lambda 主体必须使用 return 语句返回值。
- 如果功能接口方法的结果是 void,可以提供一个 return 语句,但这不是必需的。
语句块必须包含在大括号内,除非语句块是一个方法调用语句,而其调用的方法的结果是 void。Lambda 主体的结果必须与功能接口中单一方法的结果相同。
例如,如果功能接口方法的结果是 void,则 lambda 表达式主体不能返回值。如果功能接口方法具有返回类型String,则 lambda 表达式主体必须返回 String。如果 lambda 主体是一条语句,并且该方法具有一个返回类型,则该语句必须是return 语句。调用 lambda 表达式时,将运行 lambda 主体中的代码。
功能接口
Lambda 表达式与功能接口一起使用,功能接口实际上是一种只有一个抽象方法的接口;功能接口可以包含一个同时也存在于 Object 类中的方法。功能接口的示例有 java.util.concurrent.Callable(具有单一方法 call())和 java.lang.Runnable(具有单一方法run())。
区别在于,匿名接口类需要指定一个实例创建表达式,以便接口和编译器用来创建接口实现类的实例。与指定接口类型(或类类型)的匿名类不同,lambda 表达式不指定接口类型。从上下文推断为其调用 lambda 表达式的功能接口,也称为 lambda 表达式的目标类型。
Lambda 表达式的目标类型
Lambda 表达式有一个隐式的目标类型与之关联,因为未明确指定接口类型。在 lambda 表达式中,lambda 转换的目标类型必须是一个功能接口。从上下文推断目标类型。因此,lambda 表达式只能用在可以推断目标类型的上下文中。此类上下文包括
- 变量声明
- 赋值
- return 语句
- 数组初始值设定项
- 方法或构造函数的参数
- Lambda 表达式主体
- 三元条件表达式
- 转换表达式
在 Eclipse IDE 中使用 Lambda 表达式
- 1、安装了 JDK 8 的 JRE
- 2、所使用的 Eclipse 要支持 Java8 的编译
在 AndroidStudio 中使用 Lambda 表达式
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
用 Lambda 表达式创建 Hello 应用程序
我们都很熟悉 Hello 应用程序,当我们提供一个姓名时,它会输出一条消息。Hello 类声明了两个字段、两个构造函数和一个 hello()方法来输出消息,如下所示。
public class Hello {
String firstname;
String lastname;
public Hello() {
}
public Hello(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public void hello() {
System.out.println("Hello " + firstname + " " + lastname);
}
public static void main(String[] args) {
Hello hello = new Hello(args[0], args[1]);
hello.hello();
}
}
现在,我们来看看 lambda 表达式如何简化 Hello 示例中的语法。首先,我们需要创建一个功能接口,该接口包含一个返回“Hello”消息的方法。
interface HelloService {
String hello(String firstname, String lastname);
}
创建一个 lambda 表达式,它包含两个参数,与接口方法的参数相匹配。在 lambda 表达式的主体中,使用 return 语句创建并返回根据firstname 和 lastname 构造的“Hello”消息。返回值的类型必须与接口方法的返回类型相同,并且 lambda 表达式的目标必须是功能接口HelloService。
public class Test {
public static void main(String[] args) {
HelloService helloService = (String firstname, String lastname) -> {
return "Hello " + firstname + " " + lastname;
};
System.out.println(helloService.hello("包青天", "白乾涛"));
}
}
Lambda 表达式中的局部变量
- Lambda 表达式不会定义新的作用域,lambda 表达式的作用域与封闭作用域相同。如果 Lambda 主体声明的局部变量与封闭作用域内的变量重名,将产生编译器错误 Lambda expression's local variable i cannot re-declare another local variable defined in an enclosing scope
- 局部变量无论是在 lambda 表达式主体中声明,还是在封闭作用域中声明,使用之前都必须先初始化,否则将产生编译器错误 The local variable i may not have been initialized
- lambda 表达式中使用的变量必须处于终态或等效终态,否则将产生编译器错误 Variable i is required to be final or effectively final
- Lambda 主体中的 this 和 super 引用与封闭上下文中一样,因为 lambda 表达式不会引入新的作用域,这与匿名类不同。
Lambda 表达式是一种匿名方法
Lambda 表达式实际上是一种匿名方法实现;指定形式参数,并使用 return 语句返回值。匿名方法必须按照以下规则所规定的与其实现的功能接口方法兼容。
- Lambda 表达式返回的结果必须与功能接口方法的结果兼容。返回值的类型可以是功能接口方法声明中返回类型的子类型。
- Lambda 表达式签名必须与功能接口方法的签名相同。
- Lambda 表达式只能抛出那些在功能接口方法的 throws 子句中声明了异常类型或异常超类型的异常。
Lambda 表达式是一种多态表达式
Lambda 表达式的类型是从目标类型推导出来的类型。相同的 lambda 表达式在不同的上下文中可以有不同的类型。此类表达式称为多态表达式。
不支持泛型 Lambda。Lambda 表达式不能引入类型变量。