定义
Lambda 表达式,也可称为闭包,是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
语法
lambda 表达式的语法格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }
parameters
是参数列表,expression
或 { statements; }
是Lambda 表达式的主体。如果只有一个参数,可以省略括号;如果没有参数,也需要空括号。
重要特征
简洁性
Lambda 表达式提供了一种更为简洁的语法,尤其适用于函数式接口。相比于传统的匿名内部类,Lambda 表达式使得代码更为紧凑,减少了样板代码的编写。
函数式编程支持
Lambda 表达式是函数式编程的一种体现,它允许将函数当作参数传递给方法,或者将函数作为返回值,这种支持使得 Java 在函数式编程方面更为灵活,能够更好地处理集合操作、并行计算等任务。
变量捕获
Lambda 表达式可以访问外部作用域的变量,这种特性称为变量捕获,Lambda 表达式可以隐式地捕获 final 或事实上是 final 的局部变量。
方法引用
Lambda 表达式可以通过方法引用进一步简化,方法引用允许你直接引用现有类或对象的方法,而不用编写冗余的代码。
可并行性
Lambda 表达式能够更方便地实现并行操作,通过使用 Stream API 结合 Lambda 表达式,可以更容易地实现并行计算,提高程序性能。
代码例子
public class Java8Tester {
final static String salutation = "Hello! ";
public static void main(String args[]){
GreetingService greetService1 = message ->
System.out.println(salutation + message);
greetService1.sayMessage("Runoob");
}
interface GreetingService {
void sayMessage(String message);
}
}
这段 Java 代码展示了 Java 8 引入的Lambda 表达式的用法,主要用于简化函数式接口的实现。我们来逐部分解释:
代码结构解析
GreetingService
接口
这是一个函数式接口(只有一个抽象方法的接口),定义了一个sayMessage
方法,接收String
类型参数,无返回值:interface GreetingService { void sayMessage(String message); }
salutation
变量
被final static
修饰的常量,值为"Hello! "
,作用域是整个类。main
方法中的核心逻辑- 使用 Lambda 表达式创建
GreetingService
接口的实现对象greetService1
:GreetingService greetService1 = message -> System.out.println(salutation + message);
- 调用该对象的
sayMessage
方法:greetService1.sayMessage("Runoob");
- 使用 Lambda 表达式创建
Lambda 表达式的作用
Lambda 表达式在这里的作用是简化接口实现。上面的 Lambda 表达式等价于传统的匿名内部类实现:
GreetingService greetService1 = new GreetingService() {
@Override
public void sayMessage(String message) {
System.out.println(salutation + message);
}
};
message
是sayMessage
方法的参数;->
是 Lambda 运算符,分隔参数和方法体;- 右侧的
System.out.println(...)
是方法的具体实现。
为什么greetService1.sayMessage("Runoob")
在后面?
这是代码执行顺序的问题:
首先,
greetService1
是一个 “实现了GreetingService
接口的对象”,Lambda 表达式只是定义了sayMessage
方法的具体逻辑(即 “当调用sayMessage
时,要执行System.out.println(...)
”),但此时并未执行打印操作。只有当调用
greetService1.sayMessage("Runoob")
时,才会触发执行之前定义的逻辑:- 将参数
"Runoob"
传入message
; - 执行
System.out.println(salutation + message)
,即打印"Hello! Runoob"
。
- 将参数
总结
- Lambda 表达式用于定义方法的实现逻辑(相当于 “准备代码”);
- 只有调用接口的方法(如
sayMessage
)时,才会执行之前定义的逻辑; - 因此,
greetService1.sayMessage("Runoob")
必须写在 Lambda 表达式之后 —— 先定义 “要做什么”,再调用 “执行它”。
函数式接口
在 Java 中,函数式接口(Functional Interface)是指只包含一个抽象方法的接口。这类接口主要用于支持 Java 8 引入的 Lambda 表达式,使得代码可以更加简洁和灵活。
函数式接口的特点:
- 只能有一个抽象方法(可以包含多个默认方法或静态方法)
- 可以使用
@FunctionalInterface
注解进行标识(非必需,但推荐使用,编译器会帮你检查是否符合函数式接口规范) - 是 Lambda 表达式的基础,Lambda 表达式可以隐式地实现函数式接口的抽象方法
常见的内置函数式接口:
1.Consumer<T>:接收一个参数 T,无返回值(消费数据)
2.Supplier<T>:无参数,返回一个 T 类型结果(提供数据)
3.Function<T, R>:接收 T 类型参数,返回 R 类型结果(数据转换)
4.Predicate<T>:接收 T 类型参数,返回 boolean 值(条件判断)
抽象方法
在 Java 中,抽象方法(Abstract Method) 是一种没有方法体(即没有具体实现代码)的方法,它只声明了方法的名称、参数列表和返回值类型,必须由子类来实现其具体逻辑。
抽象方法的特点:
- 必须使用
abstract
关键字修饰 - 没有方法体(即没有
{}
及其中的代码),方法声明以分号;
结束 - 只能存在于抽象类(
abstract class
)或接口(interface
)中
抽象方法的作用:
抽象方法本质上是一种 "约定",它规定了子类必须实现的功能,但不限制具体实现方式。这种设计体现了"面向接口编程" 的思想
对于函数式接口来说,正因为它只有一个抽象方法,所以 Lambda 表达式才能明确地 "对应" 到这个方法,实现简洁的函数式编程。