最近在学习lambda表达式的时候,由于对书本中内容的理解处了些偏差,导致学习上绕了弯路,所以一次性把lambda表达式的部分进行整理
但需要了解的是,lambda表达式及其相关部分并未涉及到新技术或编程思想,其不过只是对于编程工作简化的“语法糖”而已
一、函数式接口
函数式接口的本质依旧是接口,但其较普通接口接口而言,函数式接口限定为内部有且只有一个抽象方法。lambda表达式就是对此类接口实例化对象过程进行简化。
而且,出于编程过程的严谨性,建议对自定义函数式接口增加@FunctionalInterface的注解
二、lambda表达式
首先来看lambda表达式的语法规则:
(参数列表) -> {lambda方法体}
其中,参数列表的括号、参数类型、方法体的大括号、方法体返回值这四部分均可视情况进行简化省略
lambda表达式的使用必须建立在对于相应函数式接口的定义的依赖上。lambda表达式的参数列表部分,是对函数式接口内部抽象方法的实参输入,而右侧的方法体是对抽象方法的具体实现代码。
而lambda的使用场景是在需要函数式接口的实现类的匿名实例对象时,从下面一个例子具体分析:
1> lambda表达式应用场景
@FunctionalInterface
public interface lambdatest{
int test(int a){
}
}
class Ltest{
public static void main(String[] args) {
//略
function(x,lambdatest A);
}
}
2> 传统方法
使用场景为function方法需要接口lambdatest的实现类的实例对象,若未使用lambda表达式,则应该写为
class Ltest{
public static void main(String[] args) {
//略
function(x,new lambdatest(){
int test(int a){
System.out.println(a);
}
});
}
}
3> lambda表达式简化后
在使用lambda表达式简化后,代码可写为
class Ltest{
public static void main(String[] args) {
//略
function(x,(int a) -> System.out.println(a));
}
}
4> 对于源码阅读后的简单总结
此部分主要参考自衣舞晨风的文章,其中涉及到Java字节码的阅读,自己也并不能很好理解,只能对结论进行整理
简单地说,代码的等效执行逻辑为
class Ltest{
//function方法定义
public static void function(int a,lambdatest A) {
A.test(a);
}
//主函数
public static void main(String[] args) {
//略
function(x,new LTest$$Lambda$1());
}
//私有静态函数
private static void lambda$main$0(String x) {
System.out.println(x);
}
//内部类
static final class LTest$$Lambda$1 implements lambdatest {
public void test(Object obj) {
LTest.lambda$main$0((int) obj);
}
private LTest$$Lambda$1() {
}
}
}
总的来看,整个编译过程如下:
- 在类编译时,会生成一个私有静态方法+一个内部类;
- 在内部类中实现了函数式接口,在实现接口的方法中,会调用编译器生成的静态方法;
- 在使用lambda表达式的地方,通过传递内部类实例,来调用函数式接口方法。
5> Lambda表达式访问其外部变量
以下内容整理自消失er的文章
- 可访问 static 修饰的成员变量,如果是 final static 修饰,不可再次赋值,只有 static 修饰可再次赋值;
- 可访问表达式外层的 final 局部变量(不用声明为 final,隐性具有 final 语义),不可再次赋值。
三、方法引用
方法引用是对lambda表达式的进一步简化,作用是定位某个静态方法或者实例方法,从而传递该方法实现函数式接口匿名实例对象,其语法形式为:
A::B
其中,A为类名或实例名,B为方法名称
主要有四种类型:
1.类名::静态方法名
2.对象::实例方法名
3.类名::实例方法名
4.类名::new
1> 类名::静态方法名
System.out::println
等价于x->System.out.println(x)
2> 对象::实例方法名
Math::pow
等价于(x,y)->Math.pow(x,y)
3> 类名::实例方法名
String::compareToIgnoreCase
等价于(x,y)->x.compareToIgnoreCase(y)
4> 类名::new (即构造器引用)
int[]::new
等价于x->new int[x]
构造器引用会传递以定位的构造方法实现抽象方法的函数式接口实例对象,在调用该实例对象的抽象方法(已被实现)时,结果是创建该构造器原属类的实例对象。