重点概念:Lambda表达式本质就是匿名内部类的匿名对象,即一个对象(这个对象类型就是你现在实现的是哪个接口,那就是哪个接口的子类实例对象,即匿名内部类对象)
但是当如果没有指定相关接口,则匿名函数就不能生成一个实例对象,不能被打印等操作,其只能当作一个函数进行传入参数使用。
底层实现:
Lambda表达式其底层是使用匿名内部类实现的,使用到ASM技术(动态写入字节码)去写了一个字节码文件(脱糖),它其实就是一个语法糖(不是JVM原生支持语法)。
执行流程:实现接口,重写接口方法,将对应字节码写出,再创建字节码或者子类实例,再赋值给函数如Consumer函数,创建实例,就实现具体函数体
注意:
(1)其中lambda表达式每次返回的对象都是不一样的。
(2)lambda表达式接口中只有一个定义的方法,但是默认或静态方法不限制
语法格式:
(1)函数体只有一个语句时候,可以省略大括号
(String mSg)-> System.out.println(“hello”+msg);
(2)只存在一个传入参数时候,省略圆括号,同时省略类型
Msg -> System.out.println(“hello”+msg);
(3)如果函数体内只有一个表达式,省略return
(int a,int b)-> a+b 等价于 (int a,int b)-> return a+b
(4)省略参数类型,编译器自行推断【因为当前函数是依据一个接口进行工作,所以接口中是有相关的返回类型等,所以可以进行自行推断,这个接口叫为函数式接口】
(a,b) -> a+b
其函数式接口为:
@FunctionalInterface
interface MyFunctionalInterface {
int add(int a,int b);
}
函数式接口不允许抛出受检异常
其实箭头就是值的赋予,像(int a,int b) ->{}就是将a,b参数赋予到后续执行代码 {} 中。
但是怎么让所声明的lambda表达式知晓到底执行的是那个接口函数?
必须使用接口对象进行确定:
@FunctionalInterface
interface MyFunctionalInterface {
int countNum(int i);
}
而我们使用其countNum方法时候就是创建接口对象且赋值:
Imath i = (x,y)->{
return x+y;
};
说白了就是对 MyFunctionalInterface接口中函数进行重写,本质也是一个函数。
但是注意,在使用lambda表达式时候仅仅是将相关接口函数进行从重写,但是并没有对其进行调用赋值,所以真正调用方法需要在进行lambda函数重写后进行。
Imath i = (x,y)->{ //规定函数真正实现逻辑
return x+y;
};
i.add(1,2); //进行相关匿名函数使用。
抽象方法只能有一个,但是实际可以在接口中,定义默认方法是没有限制的(JDK8新特性)。