记录一下Lambda表达式的东西,
一、定义
Consumer:消费者,实现accept(T t)方法
Function:apply方法,传参T,返回R
Predicate: 返回true或者false,实现test方法
Suppier: 返回一个对象,需要实现get方法。类似生产者,所以每次必须返回一个对象
基础的方法简单,需要记忆一下。
BinaryOperator:继承自BiFunction。
Consumer、Function接口都默认实现addThen方法,链式传递。其他的接口,看名字基本知道具体的作用,例如LongConsumer,参数为long类型。以Bi开头表示两个参数的意思,例如BiConsumer,BiPredicate。
函数接口(只有一个需要实现的方法,并且方法上面有@FuntionaIterface注解)的实现类,都可以使用Lambda表达式。
二、箭头函数
箭头函数主要用来简化开发,本质是一种语法糖,生成一个接口的实现类。比如定义一个Runnable 接口可以采用箭头函数方式:
Runnable runnable=()->System.out.println(hello);
所以可以把箭头函数理解成为是一个实现了某个接口方法的函数,箭头函数能够模拟的接口只允许有一个方法,default和static方法不做限制
//其实这种写法,不太好懂。可以把箭头函数理解成创建一个接口的实现类就好了
下面来个难一个一点的箭头函数:
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
这个是jdk8中的consumer接口,看这里addThen写法,return的时候,return的是一个Consumer,所以最有采用了箭头函数又生成了一个Consumer的实现类。
三、forEach
遍历操作,这种第一感觉就是要实现consumer接口的。
看下集合中forEach中的实现:
凡是继承Iterable接口的方法都具有forEach方法,因为forEach方法是Iterable的default方法。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t); }
}
最终其实还是走的for循环。HashMap采用的是类似的做法,把forEach作为map的default方法
三、Optional
jdk8新增一个工具类,可以辅助判空操作,一定要用起来,现在很多源码里面都有这个了,起码skywalking、mybatis-plus里面都有用到。
这个类的基本设计思路就是对传入进来的对象进行包装(java里面有个专业的名词叫做wrap),对包装之后的对象进行转换(map)、过滤(filter)、默认值(orElse)、获取(get)、异常(orElseThrow)、是否存在(ifPresent)。
这个工具类里面基本Consumer、Function、Supplier、Predicate基本都有涉及,是复习Lambda的好方法
- Consumer:ifPresent方法可以传入一个Consumer接口的实现类,
- Function: map,flatMap接口实现可以需要用到
- Supplier:orElse方法传入Suppier实现类
- Predicate: filter方法需要传入Predicate接口实现类
看一下filter的实现
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate); //判空操作,fast-fail
if (!isPresent())
return this; //当前对象为空,直接返回
else
return predicate.test(value) ? this : empty(); //按照传入条件进行比较
}
Optional相当于是对一个对象进行wrap,有文章说Optioanl是基于编译时的检查,这个地方不是太明白。
四、ForkJoin并行
五、Stream
//Lambda的重头戏来了
Stream是对Iterator迭代器的加强,Stream支持并行操作