lambda表达式本质上是一个匿名方法。但是,这个方法不是独立执行的,而是用于实现函数式接口定义的另一个方法。因此,lambda表达式会导致一个匿名类的生成。lambda表达式也常被称为闭包(closure)
。
函数式接口是仅包含一个抽象方法的接口。一般来说,这个方法指明了接口的目标用途。因此,函数式接口通常表示单个动作。此外函数式接口定义了lambda表达式的目标类型。特别注意 : lambda表达式只能用于已指定目标类型的上下文中。另外函数式接口有时被称为SAM(Single Abstract Method,单抽像方法)类型。
1.1 lambda表达式的基础知识
lambda表达式引入了一个新的操作符->
。它将lambda表达式分为两部分,左边制定了lambda表达式需要的所有参数,右边指定了lambda体,即lambda表达式要执行的动作。
下面来看几个简单的lambda表达式 :
() -> 12.3
: 这个lambda表达式没有参数,返回12.3() -> Math.random()*100
: 这个lambda表达式调用了Math.random()
生成一个随机数并将其*100
再返回(n) -> n % 2 == 0
: 这个lambda表达式有一个参数n, 但n为偶数时返回true,否则返回false
1.2 函数式接口
函数式接口是仅指定一个抽象方法的接口。
下面是一个标准的函数式接口
public interface MyFI {
public double getValue();
}
lambda表达式并不是独立执行的,而是构成了一个函数式接口定义的抽象方法的实现,该函数式接口定义了它的目标类型。
只有在定义了lambda表达式的目标类型的上下文中,才能使用该表达式。当把一个lambda表达式赋给一个函数式接口引用时,就创建了这样的上下文。其他类型上下文包括
变量初始化,return语句和方法参数等。
MyFI m = () -> 12.3;
当目标类型上下文中出现lambda表达式时,会自动创建实现了函数式接口的一个类的实例,函数式接口声明的抽象方法的行为由lambda表达式定义。当目标调用该方法时,就会执行lambda表达式。因此,lambda表达式提供了一种将代码片段转换为对象的方法。
System.out.println(myFI.getValue()); // 12.3
为了在目标类型上下文中使用lambda表达式,抽象方法的类型和lambda表达式的类型必须兼容。例如,如果抽象方法指定了两个int类型的参数,那么lambda表达式也必须指定两个参数,其类型要么被显示地指定为int,要么可以在上下文中被隐式地推断为int类型。lambda表达式的参数的类型和数量必须与方法的参数兼容,返回类型必须兼容,并且lambda表达式抛出的异常必须能被方法接受。
1.3 几个lambda表达式示例
package learnLambda;
/**
* 测试
*
* @author cat
* @version 2025/3/1 13:44
* @since JDK17
*/
public class Test01 {
public static void main(String[] args) {
MyFI myFI = () -> 12.3;
System.out.println(myFI.getValue());
myFI = () -> Math.random() * 100;
System.out.println(myFI.getValue());
}
}
输出 :
12.3
92.97756157149695
下面演示几个带参数的lambda表达式的使用
函数式接口
public interface MyFI02 {
boolean test(int n);
}
示例代码
package learnLambda;
/**
* 测试
*
* @author cat
* @version 2025/3/1 14:00
* @since JDK17
*/
public class Test02 {
public static void main(String[] args) {
MyFI02 fi = (n) -> n % 2 == 0;
System.out.println("fi.test(9) = " + fi.test(9));
fi = (n) -> n > 0;
System.out.println("fi.test(-1) = " + fi.test(-1));
}
}
输出 :
fi.test(9) = false
fi.test(-1) = false
如果lambda表达式只有一个参数,那么可以省略括号。
n -> n > 0