一、lambda是什么
- 函数式编程?匿名内部类?简洁?
- 来源于学术界λ,主要是行为参数化、简化内部类,在函数式接口中应用广泛。
二、为什么要学习lambda?
- 本文让你彻底学会使用lambda,不管在哪里你都能()->{} 一把嗦。
三、lambda语法
- 一个完整的lambda表达式
(Type1 param1,Type2 param2,Type3 params)->{
statement1;
statement2;
....
return data;
}
复制代码
1、()->{},lambda参数、箭头、lambda主体缺一不可
2、参数类型可以省略,而且基本都是省略
3、lambda主体中如果只有一条语句可以省略大括号、return及结尾分号
4、方法引用可以作为lambda表达式
无参lambda
- 比匿名内部类更先进,接口名称、函数名都省略了。
- lambda体只有一行,{}可以省略。
有参lambda
- 很多时候idea都能优化,但是但是。。。提交的代码库中依然一堆idea提示灰色。
四、 函数式接口
- 能够使用lambda的依据是函数式接口,即内部只有一个抽象方法的接口,并非只有一个方法。
- lambda表达式的类型推断也是跟函数式接口有关,编译器能根据上下文信息推断出参数类型。
几个典型的函数式接口
1、BiFunction
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
复制代码
image.png1、这个函数式接口在java 8 stream中大量使用。
2、有2个方法,只有1个抽象方法
3、抽象方法apply接受2个参数,类型是T,U,返回值是R。
4、下面的get()第三个参数的BiFunction函数式接口,因此你在调用get()可以传递一个符合该函数式接口规范的lambda。至于参数1、参数2怎么操作、运算、加密。。。依赖于你的lambda主体。
2、Consumer
- 消费函数,返回值为void。
@FunctionalInterface
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); };
}
}
复制代码
- 返回值void,故一般使用其副作用。
3、Predicate
- 断言/条件测试,定义一个抽象方法,必定有1个入参,返回值boolean。
- 最常用在stream中的filter(),可以组成predicate调用链。
//以下都可以做一个Predicate的lambda
1、(s)->s.length()>0;
2、(v)->v > 100;
3、(o)->o.startWith("a");
复制代码
4、Supplier
- 不需要输入,产出T。像是一个容器,调用get返回对象。
Supplier<Integer> supplier = new Supplier<Integer>() {
@Override
public Integer get() {
//返回一个随机值
return new Random().nextInt();
}
};
System.out.println(supplier.get());
System.out.println(supplier.get());
复制代码
方法引用
- 简单来讲就是让你可以重复使用现有的方法定义,并像lambda一样传递他们,使用::来表示。主要有三类。
- 核心点:函数签名要符合,即传参类型、参数数量、返回值类型还是void。
1、静态方法的方法引用
- 静态方法作用于对象上。
public static void main(String[] args) {
List<String> list = Lists.newArrayList("1","2","3","4");
List<Integer> collect1 = list.stream().map(v -> Integer.parseInt(v))
.collect(Collectors.toList());
List<Integer> collect2 = list.stream().map(Integer::parseInt)
.collect(Collectors.toList());
}
复制代码
2、指向 任意类型实例方法 的方法引用
1、这个任意类型一般指的是你的lambda的入参类型。
2、如下面的入参是v,调用v.length可以写作v的类型String::length。
public static void main(String[] args) {
List<String> list = Lists
.newArrayList("hello", "how", "are", "you", "i", "am", "fine", "thank", "you", "and",
"you");
Set<Integer> collect = list.stream().map(v -> v.length()).collect(Collectors.toSet());
Set<Integer> collect1 = list.stream().map(String::length).collect(Collectors.toSet());
System.out.println(collect);
System.out.println(collect1);
}
复制代码
3、指向既有对象的方法的方法引用
- 与上述第2点类似,不详细说明。
五、小结
- 主要介绍了lambda表达式及函数式接口
- 使用函数式接口的核心就是搞对函数签名,传入一个符合条件签名的lambda,就可以()->{}一把唆了。
网友评论