Java8 Lambda表达式、函数式接口和方法引用
阅读原文时间:2023年07月10日阅读:1

目录

Java8 Lambda表达式和函数式接口

Lambda表达式是一个匿名函数

本质

函数式接口的实例

作用

语法糖,代替匿名实现类对象

核心思路

可推断的可省

格式

()->{}

() Lambda形参列表,接口中的抽象方法的形参列表

-> Lambda操作符,箭头操作符

{} Lambda体,重写的抽象方法的方法体

使用场景:当需要对一个函数式接口实例化时 -> 用匿名实现类实现的都可以用Lambda表达式

Lambda表达式可以看成函数式接口实现类的对象(实例) -> 以前用匿名实现类表示的现在可以用Lambda表达式来写

Lambda的使用

Lambad形参列表

1.只有一个参数 -> 小括号可以省略

2.参数类型可以推断出来(基本都行) -> 可以省略

Lambda体

只有一条语句 -> 大括号、return可以省略

Comparator <Double> com = new Consumer<Double>() {
     @Override
     public void accept(Double aDouble) {
     System.out.println("购物花了"+aDouble);
      }
})

/*
简化1:Comparator <Double> com  Double可以推断出 new Consumer<Double>()与Double aDouble里的类型为Double
Comparator <Double> com = new Consumer<>(){
     public void accept(aDouble) {
     System.out.println("购物花了"+aDouble);
      }
}

简化2:Consumer为函数式接口
接口只声明了一个抽象方法 -> 所以实现类实现的方法只能是此方法,所以可以省略
Comparator <Double> com = aDouble -> System.out.println("购物花了"+aDouble)

*/

//Lambda表达式
Comparator <Integer> -com = aDouble -> System.out.println("购物花了"+aDouble)

定义

接口只声明了一个抽象方法,实现类只能实现该方法所以可以省略new Runnable(){@ovverride public void run}

表示

@FunctionalInterface

说明

Lambda表达式可以看成函数式接口实现类的对象 -> 以前用匿名实现类表示的现在可以用Lambda表达式来写

java.util.funciton包下定义了java8的函数式接口

Java内置四大核心函数式接口

函数时式接口

参数类型

返回类型

用途

Consumer消费型接口

T

void

对类型为T的对象应用操作,包含方法:void accept(T t),接受一个参数不返回

Supplier供给型接口

T

返回类型为T的对象,包含方法:T get(),不提供参数返回一个值

Function函数型接口

T

R

对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)

Predicate断定型接口

T

boolean

确定类型为T的对象是否满足某约束,并返回boolean值,包含方法:boolean test(T t) 根据一定的规则过滤

如果自定义的接口符合上述接口的特征,就没有必要自己定义,直接使用就可以了。

class Test{
    public  void test(){
      //原来的写法
      happyTime(500, new Consumer<Double>() {
         @Override
         public void accept(Double aDouble) {
         System.out.println("购物花了"+aDouble);
          }
        });

        //Lambda表达式
        happyTime(600,aDouble -> System.out.println("购物花了"+aDouble));
    }
}

/具体的Consumer接口实现类由调用函数时确定
 public void happyTime(double money, Consumer<Double> con){
        con.accept(money);  //accept为Consumer的抽象方法
}

使用情况

当要传递给Lambda体{}的操作,已经有实现方法(不需要我们自己去写,直接调用写好的方法)了,可以使用方法引用。

说明

方法引用就是Lambda表达式,也是函数式接口的一个实例,通过方法的名字来指向一个方法,也就是Lambda表达式的语法糖。

要求

实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致(针对情况1和情况2)

//这里的直接调用写好的方法
//Integer.compare方法引用的参数列表o1,o2,返回值为int
//Comparator实现类的列表和返回值也是一样的,所以可以使用方法引用
Comparator<Integer> com = (o1,o2) -> Integer.compare(o1,o2);

//方法引用
Comparator<Integer> com = Integer::compare

格式

情况1.对象::非静态方法

情况2.类::静态方法

情况3.类::非静态方法

//Consumer中的抽象方法void accept(T t)
//方法引用的方法:PrintStream中的void println(T t)
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("北京");
System.out.println("*******");

//方法引用替换的是Lambda体

//情况1:对象::非静态方法
PrintStream ps = System.out;
Consumer  <String> con2 = ps::println;
con1.accept("beijing");

//情况2:类::静态方法
Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1,t2);
System.out.println(com1.compare(12, 21));
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(12, 21));

//情况3:类::非静态方法
//Comparator中的int compare(T t1,T t2)
//String中的int t1.compareTO(t2)
//第一个参数t1调用了,在参数列表就没有必要写了,方法引用时的类就是调用者的类  这样才保证参数都使用上了
Comparator<String> com3 = (s1,s2) -> s1.compareTo(s2);
System.out.println(com3.compare("abc", "abd"));
Comparator<String> com4 = String::compareTo;
System.out.println(com4.compare("abc", "abd"));

构造器引用

类似方法引用.函数式接口的抽象方法的形参列表和构造器的形参列表一致

抽象方法的返回值类型即为构造器所属的类的类型,也就是写在冒号前面的类

//构造器引用
//Supplier中的T get()
//Employee的空参构造器Employee()
Supplier <Employee> sup1 = () -> new Employee();
Supplier <Employee> sup2 = Employee::new;

//Function中的R apply(T t)
Function<Integer,Employee> func1 = id-> new Employee(id);
func1.apply(1001);
Function<Integer,Employee> func2 = Employee::new;
func2.apply(1002);