前言
作为匿名参数,Lambda 给我们带来了简洁、直观的函数表达,便于后期维护与二次开发。有关 Lambda 表达式的一切内容,将在本文呈现。
提示:以下是本篇文章正文内容,下面案例可供参考
一、Lambda介绍
可以理解为简洁地表示可传递的 匿名函数的一种方式:它没有名称,但它有参数列表 、函数主体、返回类型,可能还有一个可抛出的异常列表。
- 匿名——不需要函数名称
- 函数——和普通函数一样,Lambda有参数列表、函数主体、返回类型,还可能有可抛出的异常列表
- 传递——Lambda表达式可作为参数传递给方法或存储在变量中
- 简洁——无需像匿名类写很多模板代码
组成
- 参数列表
- 箭头:分隔参数列表与Lambda主体
- Lambda主体
基本语法
(parameters) -> expression
(parameters) -> { statements; }
二、Lambda使用场景
- 函数式接口:只定义一个抽象方法的接口。
注意:接口可以拥有默认方法,哪怕有很多默认方法 ,只要接口只定义了一个抽象方法,它就仍然是一个函数式接口 - 函数描述符:函数式接口的抽象方法的签名与Lambda函数的签名一致,将这种抽象方法叫做函数描述符
补充:方法的名字和參数列表成为方法的签名
三、环绕执行模式
环绕执行模式:初始化/准备代码 --> 任务 A/B --> 清理/结束代码
- 记得行为参数化
String result = processFile((BufferedReader br) -> br.readLine() + br.readLine());
- 使用函数式接口来传递行为
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
// 现在可以用这个接口作为新的 processFile 方法的参数
public static String processFile(BufferedReaderProcessor p) throws IOException {
...
}
- 执行一个行为
public static String processFile(BufferedReaderProcessor p) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
// 处理 BufferedReader 对象
return p.process(br);
}
}
- 传递Lambda
String oneLine = processFile((BufferedReader br) -> br.readLine());
String twoLine = processFile((BufferedReader br) -> br.readLine() + br.readLine());
四、原始类型特化
原始类型特化
Java类型
- 引用类型(Byte、Integer、Object、List)
- 原始类型(int、double、byte、char)
泛型(比如Consumer中的T)只能绑定引用类型,Java提供一套原始类型与引用类型转化的机制
- 装箱:原始类型 --> 引用类型,本质上把原始类型包裹起来,并保存在堆里,需要更多内存,需要额外的内存搜索来获取被包装的原始值
- 拆箱:引用类型 --> 原始类型
原始类型特化避免了上述的装箱操作
函数式接口 | 函数描述符 | 原始类型特化 |
---|---|---|
Predicate | T -> boolean | IntPredicate, LongPredicate, DoublePredicate |
Cosumer | T->void | IntConsumer, LongConsumer, DoubleConsumer |
Function<T, R> | T -> R | IntFunction, IntToDoubleFunction, IntToLongFunction, LongFunction, LongToDoubleFunction, LongToIntFunction, DoubleFunction, ToIntFunction, ToDoubleFunction, ToLongFunction |
Supplier | () -> T | BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier |
UnaryOperator | T -> T | IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator |
BinaryOperator | (T, T) -> T | IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator |
BiPredicate<L, R> | (L, R) -> boolean | |
BiConsumer<T, U> | (T, U) -> void | ObjIntConsumer, ObjLongConsumer, ObjDoubleConsumer |
BiFunction<T, U, R> | (T, U) -> R | ToIntBiFunction<T, U>, ToLongBiFunction<T, U>, ToDoubleBiFunction<T, U> |
五、方法引用
基本思想:如果一个Lambda代表的只是“直接调用这个方法”,最好用名称来调用,而不是去描述如何调用它。
Lambda | 等效的方法引用 |
---|---|
(Apple a) -> a.getWeight() | Apple::getWeight |
()->Thread.currentThread().dumpStack() | Thread.currentThread()::dumpStack |
(str, i) -> str.substring(i) | String::substring |
(String s) -> System.out.println(s) | System.out::println |
分类:
- 指向静态方法的方法引用:例如 Integer 的 parseInt 方法,Integer::parseInt
- 指向任意类型实例方法的方法引用:例如 String 的 length 方法,String::length
- 指向现有对象的实例方法的方法引用:假设有一个局部变量 expensiveTransaction 用于存放 Transaction 类型的对象,它支持实例方法 getValue,可以写 expensiveTransaction::getValue
构造函数引用
Supplier<Apple> c1 = Apple::new;
Apple a1 = c1.get();
// 构造函数签名是 Apple(Integer, weight)
Function<Integer, Apple> c2 = Apple::new;
Apple a2 = c2.apply(110);
总结
以上就是 Lambda 表达式的内容,本文介绍了Lambda表达式的组成、基本语法以及使用场景,又梳理了与 Lambda 表达式相关的环绕执行模式、原始类型特化以及方法引用。
@北京·海淀 2020.12.13