lambda表达式:
使用场景:
1.使用lambda表达式是为了简化接口实现,本质上只是一个匿名函数,可以使用这个匿名函数实现接口中的方法,对接口进行非常简单的实现,从而简化代码
2.lanbda表达式是能实现函数式接口
函数式接口的概念:
如果说,一个接口中要求实现磊必须实现的抽象方法,有且只有一个,这样的接口,就是函数式接口
@FunctionalInterface:是一个注解,用在接口之前,判断这个接口是否是一个函数式接口,如果是一个函数式接口,如果不是函数时接口,没有问题,但如果不是函数式接口,则会报错,功能类似于@Override
语法:
lambda表达式,本质上来讲就是一个匿名函数,因此在写lambda表达式的时候,不需要关心方法名是什么,实际上,我们在写lambda表达式的时候,也不需要关心返回值类型,只需要关注两部分内容:参数列表和方法体
(参数)->{
方法体
};
/*
参数部分:方法的参数列表,要求和实现的接口中的方法参数部分一致,包括参数的数量和类型
方法体部分:方法的实现部分,如果接口中定义的方法有返回值,则在实现的时候,注意返回值的返回
->:分隔参数部分和方法体部分
*/
lambda表达式的进阶:
参数部分的精简:
参数的类型:
由于在接口的方法中,已经定义了每一个参数的类型是什么,而在使用lambda表达式实现接口的时候,必须保证参数的数量和类型需要和接口中方法保持一致,因此lambda表达式中的参数可以省略不写
(注意事项):
如果需要省略参数的类型,要保证:每一个参数的类型都省略不写,绝对不能出现,有的参数省略了,有的参数没有省略。
-----------------------------------------------------------------------------------
参数的小括号:
如果方法的参数列表中的参数数量有且仅有一个,此时的小括号是可以省略不写的
(注意事项):
只有当参数的数量是一个的时候,多了,少了都不能省略
省略掉小括号时,必须要省略参数的类型
方法体部分的精简:
方法体中的大括号的精简:
当方法体中的逻辑,有且仅有一句的情况下,大括号可以省略不写
return的精简:
如果一个方法中的唯一的一条语句是一个返回语句,此时在省略大括号的同时,也必须省略掉return
函数引用:
lambda表达式是为了简化接口的实现。在lambda表达式中,不应该出现比较复杂的逻辑,如果在lambda表达式中出现了过于复杂的逻辑,会对程序的可读性造成非常大的影响,如果在lambda表达式中需要处理的逻辑比较复杂,一般情况下会单独的写一个方法,在lambda表达式中直接引用这个方法即可
或者在一些情况下,我们需要使用lambda表达式中实现的逻辑,在另一个地方已经写好了,此时我们就不需要再单独写一遍,只需要引出这个一斤存在的方法即可
函数引用:引用一个已经存在的方法,使其替代lambda表达式完成接口的实现
静态方法的引用:
package bk.javase.p528;
/*
静态方法的引用:
注意事项:
在引用方法的后面,不需要添加小括号
引用这个方法,参数(数量,类型)和返回值,必须和接口中定义的一致
*/
public class demo5 {
public static void main(String[] args) {
//实现对一个或多个参数的,一个返回值的接口
//对一个静态方法的引用
//语法:类名::静态方法
SingleReturnMutiple lambda1 = Calculator::calculate;
System.out.println(lambda1.test(10,20));
}
private static class Calculator{
public static int calculate(int a,int b){
//我们将稍微复杂的计算逻辑放到方法中
if (a > b){
return a-b;
}else{
return b-a;
}
}
}
}
@FunctionalInterface
interface SingleReturnMutiple{
int test(int a,int b);
}
非静态方法的引用:
package bk.javase.p528;
/*
非静态方法的引用:
注意事项:
在引用的方法后面,不要添加小括号
引用的这个方法,参数(数量,类型)和返回值,必须和接口中定义的一致
*/
public class demo6 {
public static void main(String[] args) {
//对非静态方法的引用,需要使用对象来完成
//语法:匿名对象::非静态类方法
SingleReturnMutipleParameters lambda = new Calculator()::calculate;
System.out.println(lambda.test(10,20));
}
private static class Calculator{
public int calculate(int a,int b){
return a > b ?a-b:b-a;
}
}
}
@FunctionalInterface
interface SingleReturnMutipleParameters{
int test(int a,int b);
}
构造方法的引用:
package bk.javase.p528;
/*
构造方法的引用:
如果在一个函数式接口定义的方法,仅仅是为了得到一个类的对象,
此时我们就可以使用构造方法的引用,简化这个方法的实现
注意事项:
可以通过接口中的方法的参数,区分不同的构造方法
*/
public class demo7 {
public static void main(String[] args){
//lambda表达式实现接口
GetPerson lambda = Person::new;
//引用到Person类中的无参构造方法,获取到一个Person对象
Person person = lambda.test();
//引用到Person类中的有参构造方法,获取到一个Person对象
GetPersonParameter lambda2 = Person::new;
lambda2.test("xiaoming",1);
}
private static class Person{
String name;
int age;
public Person(){
System.out.println("一个Person对象被实例化了");
}
public Person(String name,int age){
System.out.println("一个Person对象被有参构造实例化了");
this.name = name;
this.age = age;
}
}
@FunctionalInterface
private interface GetPerson{
//仅仅是希望获取到一个Person对象作为返回值
Person test();
}
private interface GetPersonParameter{
Person test(String name,int age);
}
}
对象方法的特殊引用:
package bk.javase.p528;
/*
对象方法的特殊引用
如果在使用lambda表达式,实现某些接口时,lambda表达式中包含了某一个对象,此时方法体中
直接使用这个对象调用它的某一个方法就可以完成整体的逻辑,其他的参数,可以作为调用方法的参数
此时,可以对这种实现进行简化
*/
public class demo8 {
public static void main(String[] args){
//如果对于这个方法的实现逻辑,是为了获得到对象的名字
GetField field = person -> person.getName();
//对于对象方法的特殊引用
GetField fields = Person::getName;
//如果对于这个方法的实现逻辑,是为了给对象的某些属性进行赋值
SetField lambda = (person,name)->person.setName(name);
SetField lambda2 = Person::setName;
}
}
interface ShowTest{
void test(Person person);
}
interface SetField{
void set(Person person,String name);
}
interface GetField{
String get(Person person);
}
class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
}
}
使用lambda表达式要注意的问题:
类似于局部内部类,匿名内部类,依然存在闭包的问题
如果在lambda表达式中,使用到了局部变量,那么这个局部变量会被隐式的声明为final,放到常量池中,是一个常量,不能修改值