Java中的Lambda表达式
含义:
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 表达式是使用最小可能语法编写的函数定义:
-
Lambda 表达式产生函数,而不是类。 虽然在 JVM(Java Virtual Machine,Java 虚拟机)上,一切都是类,但是幕后有各种操作执行让 Lambda 看起来像函数 —— 作为程序员,你可以高兴地假装它们“就是函数”。
-
Lambda 语法尽可能少,这正是为了使 Lambda 易于编写和使用。
函数式接口
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
注意: 函数式接口可包含默认的方法
// 1. 定义一个函数式接口
interface ILike{
void lambda();
default public void print(){
System.out.println("hah");
}
}
lambda 演变过程
public class LambdaTest {
public static void main(String[] args){
ILike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
// 4. 局部内部类
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
like = new Like3();
like.lambda();
// 5. 匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike(){
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
// 6. 用lambda简化
like = () ->{
System.out.println("i like lambda5");
};
like.lambda();
}
}
// 2. 实现类
class Like implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
lambda表达式特征
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
案例
//单个参数
like = (words) ->{
System.out.println("i like " + words);
};
like.lambda("lambda");
//多个参数
like = (String words, int year) ->{
System.out.println("i like " + words);
System.out.println("this year is " + year);
};
like.lambda("lambda",2021);
方法引用
- 对象::实例方法,将lambda的参数当作方法的参数使用
/**
*print(String x)的签名(参数类型和返回类型)符合ILike的lambda(String worlds)签名
*/
ILike like = System.out::print;
//等效
ILike like = (x)->System.out.print(x);
- 类::静态方法,将lambda的参数当做方法的参数使用
//ClassName::staticMethod 类的静态方法:把表达式的参数值作为staticMethod方法的参数
Function<Integer, String> sf = String::valueOf;
//等效
Function<Integer, String> sf2 = (x) -> String.valueOf(x);
String apply = sf.apply(61888);
//Function接口,接受两个类型为T,R的参数, 调用apply(T t)方法,返回T类型的结果。
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
...
}
- 类::实例方法,将lambda的第一个参数当做方法的调用者,其他的参数作为方法的参数。
//ClassName::instanceMethod 类的实例方法:把表达式的第一个参数当成instanceMethod的调用者,其他参数作为该方法的参数
BiPredicate<String, String> sbp = String::equals;
//等效
BiPredicate<String, String> sbp2 = (x, y) -> x.equals(y);
boolean test = sbp.test("a", "A");
@FunctionalInterface
public interface BiPredicate<T, U> {
/**
* Evaluates this predicate on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
* @return {@code true} if the input arguments match the predicate,
* otherwise {@code false}
*/
boolean test(T t, U u);
...
}
构造函数
无参的构造方法,类::实例方法模型。
Supplier<User> us = User::new;
//等效
Supplier<User> us2 = () -> new User();
//获取对象
User user = us.get();
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
* @return a result
*/
T get();
}
有参构造函数
//一个参数,参数类型不同则会编译出错
Function<Integer, User> uf = id -> new User(id);
//或加括号
Function<Integer, User> uf2 = (id) -> new User(id);
//等效
Function<Integer, User> uf3 = (Integer id) -> new User(id);
User apply = uf.apply(1002);
//两个参数
BiFunction<Integer, String, User> ubf = (id, name) -> new User(id, name);
User 狂欢happy = ubf.apply(1001, "lucy");
Java 8 引入了 java.util.function 包。它包含一组接口,这些接口是 Lambda 表达式和方法引用的目标类型。 每个接口只包含一个抽象方法,称为 函数式方法 。