Lambda属于函数式编程
为什么使用Lambda表达式
- 避免匿名内部类定义过多
- 可以让你的代码看起来很简洁
- 去掉一堆没有意义的代码,只留下核心的逻辑
函数式接口
JDK 1.8 新增加的函数接口:java.util.function
函数式接口的定义:任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口。
使用@FunctionalInterface注解可以检测该接口是否为函数式接口
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
java.util.function 它包含了很多类,用来支持 Java 的 函数式编程,该包中的函数式接口主要有:
四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
Consumer 消费型接口 | T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier 供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get() |
Function<T, R> 函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) |
Predicate 断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean 值。包含方法:boolean test(T t) |
其他接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
BiFunction<T, U, R> | T, U | R | 对类型为 T, U 参数应用操作,返回 R 类型的结 |
UnaryOperator (Function子接口) | T | T | 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为:T apply(T t); |
BinaryOperator | T, T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为: T apply(T t1, T t2); |
BiConsumer<T, U> | T, U | void | 对类型为T, U 参数应用操作。包含方法为: void accept(T t, U u) |
BiPredicate<T,U> | T,U | boolean | 包含方法为: boolean test(T t,U u) |
ToIntFunction ToLongFunction ToDoubleFunction | T | int long double | 分别计算int、long、double值的函数 |
IntFunction LongFunction DoubleFunction | int long double | R | 参数分别为int、long、double 类型的函数 |
Lambda表达式
学习Lambda表达式,需要理解函数式接口(Function Interface)
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
Consumer consumer = (o)-> System.out.println(o);
看到现在不是还有点懵,没关系,我们来看看jdk8之前我们怎么实现一个接口的,Lambda是怎么慢慢简化来的
//1.实现类
public class MyConsumer implements Consumer{
public void accept(Object o) {
System.out.println(o);
}
}
public class TestLambda1{
//2.静态内部类
static class MyConsumer implements Consumer{
@Override
public void accept(Object o) {
System.out.println(o);
}
}
public static void main(String [] args){
//3.局部内部类
class MyConsumer implements Consumer{
public void accept(Object o) {
System.out.println(o);
}
}
//4.匿名内部类
Consumer MyConsumer = new Consumer() {
@Override
public void accept(Object o) {
System.out.println(o);
}
};
//5.Lambda表达式
Consumer MyConsumer1 = (o) -> System.out.println(o);
}
}
从1-5可以看出,接口的实现类慢慢从外部到内部,然后到局部,从一开始的多行代码,到最后简单的一行代码解决,可以看出Lambda表达式就是为了简化代码,去掉一堆没有意义的代码,只留下核心的逻辑,但是用Lambda写出来的代码虽然简洁,但是对于阅读来说不够友好
接下来我们看一下Lambda的几种情景和写法
public class TestLambda2{
public static void main(String [] args){
Consumer consumer = null;
//情况1:无参无返回,一行代码,省去大括号
Runnable run = () -> System.out.println("Runnable接口");
//情况2:无参无返回,多行代码
Runnable run1 = () -> {
System.out.print("Runnable");
System.out.println("接口");
};
//情况3:一个参数,无返回
//写法1
consumer = (Object o) -> System.out.println(o);
//写法2:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”
consumer = (o) -> System.out.println(o);
//写法3:若只需要一个参数时,参数的小括号可以省略,多个参数不能省去小括号
consumer = o -> System.out.println(o);
//情况4:两个或以上的参数,多条执行语句,并且可以有返回值
Comparator<Integer> com1 = (o1,o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
//情况5:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略
Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
}
}
注意
Java 8 在类型推测方面有了很大的提高,这就使代码更整洁,不需要太多的强制类型转换了。
首先,在Lambda中去掉参数类型,是类型推测的一种,还有其他常用的如下例子
//原
ArrayList<String> list = new ArrayList<String>();
//类型推断
ArrayList<String> list = new ArrayList<>();
//原
int[] arr = new int[]{1,2,3};
//类型推断
int[] arr = {1,2,3};