1、表达式语法
1)lambda 的命名采用的是数学符号 λ;
2)lambda 表达式是一个可传递的代码块,可以用一个函数式接口接收,表示形式如下:
1、参数 ->(箭头)表达式;
(String first, String second) -> first.length() - second.length();
2、表达式可以是一条语句,也可以是 {} 括号的代码块;
(String first, String second) -> {
return first.length() - second.length();
}
3、lambda 表达式没有参数时也要使用 () 表示空参数,就像方法没有参数;
() -> {
return System.out.println("lambda");
}
4、如果能够推导出参数的类型,那参数部分可以不使用类型;
(first, second) -> {
return first.length() - second.length();
};
5、只有一个参数时,且能够推导出参数类型,则可以不使用小括号;
first -> {
return first.length();
}
6、lambda 表达式有返回类型时:
①、一条语句不需要用 return 返回,因为可以推导出;
first -> first.length() ;
②、在 {} 代码块中的需要用 return 返回;
first -> {
return first.length();
};
7、lambda 表达式没有返回类型时,不需要使用 return;
first -> first.length() ;
first -> {
first.length();
};
2、函数式接口
1)任何只有一个抽象方法的接口都是函数式接口,如下就是一个自定义的函数式接口;
2)@FunctionalInterface,可以使用该注解标记函数式接口,当然也可以不用该注解标记。使用该注解有以下两个好处;
1、当在接口中再新加一个抽象方法时,会报编译错误,很明显的知道;
2、在 javadoc 文档中会标记自定义的接口是函数式接口;
3)lambda 表达式的代码块其实就是函数式接口的抽象方法的实现;
1、当一个函数式接口作为一个方法(A)的入参时,我们以前是用一个类实现该接口,并实现接口中的抽象方法,然后传实现类给方法(A),在执行的时候会执行实现类中的方法;
2、使用 lambda 表达式;
4)在 java 中 lambda 表达式只能是转换为函数式接口,即 lambda 表达式是传递给方法中函数式接口参数的;
5)lambda 表达式不能赋给 Object 类型的变量,因为 Object 类不是函数式接口,只能赋给函数式接口的变量,即只能用函数式接口来接收;
6)特定的函数式接口在 java.util.function 包中;
3、方法引用
1)方法引用可以认为是 lambda 表达式的简写;
2)方法引用和 lambda 表达式一样在赋值给函数式接口变量时会生成一个对象;
解析:
1、Arrays.sort 方法第二个参数是 Comparator 接口(是一个函数式接口),在传 lambda 表达式和方法引用时会生成一个对象传给 Comparator 接口,lambda 表达式的代码块或方法引用时的方法会成为该生成对象的对 Comparator 接口抽象方法的实现内容;
2、由编译器生成;
3)使用方法引用时如果遇到多个重载方法,编译器会选择一个最合适的重载方法;
4)方法引用的三种情况:
1、object::instanceMethod
等价于向方法传递参数的 lambda 表达式,
如:System.out::println <==> x -> System.out.println(x),这里 out 是一个对象,把参数 x 传递给 println 方法;
2、Class::instanceMethod
等价的 lambda 表达式是,第一个参数是作为隐式参数,后面的参数作为传递给方法的参数,
如:
String::compareToIgnoreCase <==> (x, y) -> x.compareToIgnoreCase(y),第一个参数 x 是隐式参数,也即调用的方法;
3、Class::staticMethod
等价的 lambda 表达式是,所有的参数都传递给静态方法,
如:Math::pow <==> (x, y) -> Math.pow(x, y);
5)只有当 lambda 表达式的体调用一个方法的时候,才能把 lambda 表达式重写为方法引用;
1、object::instanceMethod
2、Class::instanceMethod
3、Class::staticMethod
6)方法引用时可以使用 this / super 参数;
this::equals <==> x-> this.equals(x);
super::instanceMethod;
4、构造器引用
1)Person::new <==> (xxx...) -> new Person(xxx...);
构造器方法的选择是根据上下文自动选择的,会选择出合适的参数的构造器方法;
2)Person[]::new <==> n -> new Person[n];
3)不管是方法引用还是构造器引用,都会转为等价的 lambda 表达式,而 lambda 表达式会作为函数式接口的实现往下传;
5、变量作用域
1)在 lambda 表达式中可以访问所属方法或类中的变量;
2)lambda 表达式是传递给函数式接口的,相当于是函数式接口的实现,lambda 表达式使用所属方法中的变量,就相当于把变量传递给函数式接口的实现类的方法;
3)lambda 表达式使用所属方法中的变量时会存储一份该变量的值,即 lambad 表达式可以捕捉到外围作用域中变量的值;
4)lambda 表达式只可以引用值不会改变的外围作用中的变量;
5)lambda 表达式捕捉的变量必须是事实最终变量,事实最终变量是指该变量初始化之后就不会再赋值;
6)lambda 表达式中不能定义与外围作用域中同名的变量;
7)lambda 表达式内不能定义同名的变量;
8)在 lambda 表达式中使用 this 关键字时,该 this 关键字表示的 lambda 表达式所属方法所在的对象;