Lambda表达式
一、Lambda简介
1.1、前置知识
函数式接口,若某接口中有且只有一个必须被实现的抽象方法,则该接口就是函数式接口。函数式接口可以被@FunationalInterface注解标识。
Java8 提供一个default关键字,接口中被default关键字修饰的抽象方法都会有其默认实现,而且该抽象方法可以不被实现,并不属于必须被实现的抽象方法。
符合函数式接口的接口,如下:
@FunctionalInterface
public interface UserService {
// 添加用户信息
void addUser(User user);
}
@FunctionalInterface
public interface PersonService {
// 删除用户信息
void removePersonById(Long personId);
// 修改用户信息
default modifyPerson(Person person);
}
@FunctionalInterface
public interface AccountService {
// 查询指定id的账户信息
Account findAccount(Long accountId);
// 添加账户信息
default addAccount(Account account);
// 修改账户信息
default modifyAccount(Account account);
// 删除账户信息
default removeAccount(Long accountId);
}
1.2、简介
Lambda表达式是 Java8 添加的一种新特性,可以将其看作是一个匿名方法,以一种极简的方式来实现函数式接口那个必须实现的抽象方法。
三种实现接口方式的对比,如下:
@FunctionalInterface
public interface Calculator {
int add(int num1, int num2);
}
1)通过接口实现类的方式实现接口,如下:
public class CalculatorImpl implements Calculator {
@Override
public int add(int num1, int num2) {
return num1 + num2;
}
}
public class TestDemo {
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
System.out.println(calculator.add(2, 3));
}
}
2)通过匿名内部类的方式实现接口,如下:
public class TestDemo {
public static void main(String[] args) {
Calculator calculator = new Calculator() {
@Override
public int add(int num1, int num2) {
return num1 + 1num2;
}
};
System.out.println(calculator.add(1, 2));
}
}
3)通过Lambda表达式的方式来实现接口。如下:
public class TestDemo {
public static void main(String[] args) {
Calculator calculator = (num1, num2) -> num1 + num2;
System.out.ptintln(calculator.add(5, 6));
}
}
结论:在三种实现接口的方式中,Lambda表达式方式的代码最简洁,但Lambda表达式存在局限性,它只能实现函数式接口。
二、语法
2.1、基础语法
Java中的方法由方法返回值类型、方法名、参数列表和方法体四部分组成,由于Lambda表达式本身就是一个匿名方法且并不关注方法返回值类型,所以Lambda表达式是由参数列表和方法体组成。结构如下:
(参数列表) -> {
方法体;
}
注意:
1、小括号中的内容是方法的参数列表,里面只需要添加形参变量,无需添加形参变量的数据类型;
2、->,是Lambda表达式的运算符,读作 " goes to",;
3、大括号中的内容是方法的方法体;
扩展:
为什么Lambda表达式的参数列表中无需声明形参类型呢?
首先Lambda表达式不会发生重载现象,既然在函数式接口中,方法的所有形参类型已经声明,那么Lambda表达式只要按照参数顺序添加形参变量即可。
1)创建6种函数式接口,如下:
@FunctionalInterface
public interface LambdaNoReturnNoParameter {
void test();
}
@FunctionalInterface
public interface LambdaNoReturnSingleParameter {
void test(int a);
}
@FunctionalInterface
public interface LambdaNoReturnMultipleParameters {
void test(int a, int b);
}
@FunctionalInterface
public interface LambdaSingleReturnNoParameter {
int test();
}
@FunctionalInterface
public interface LambdaSingleReturnSingleParameter {
int test(int a);
}
@FunctionalInterface
public interface LambdaSingleReturnMultipleParameters {
int test(int a, int b);
}
2)使用Lambda表达式实现接口,如下:
public class LambdaImplFunctionalInterface {
public static void main(String[] args) {
// 1、Lambda表达式实现无参无返回的函数式接口
LambdaNoReturnNoParameter noNo = () -> {
System.out.println("Hello,Lambda!");
};
noNo.test();
// 2、使用Lambda表达式实现单参无返回的函数式接口
LambdaNoReturnSingleParameter noSingle = (int a) -> {
System.out.println("Hello,Lambda! " + a);
};
noSingle.test(10);
// 3、使用Lambda表达式实现多参无返回的函数式接口
LambdaNoReturnMultipleParameters noMultiple = (int a, int b) -> {
System.out.println("Hello,Lambda! " + a + " " + b);
};
noMultiple.test(10,20);
// 4、使用Lambda表达式实现无参有返回的函数式接口
LambdaSingleReturnNoParameter singleNo = () -> {
System.out.println("Hello,Lambda!");
return 10;
};
System.out.println(singleNo.test());
// 5、使用Lambda表达式实现单参有返回的函数式接口
LambdaSingleReturnSingleParameter singleSingle = (int a) -> {
System.out.println("Hello,Lambda!");
return a;
};
System.out.println(singleSingle.test(20));
// 6、使用Lambda表达式实现多参有返回的函数式接口
LambdaSingleReturnMultipleParameters singleMultiple = (int a, int b) -> {
System.out.println("Hello,Lambda!");
return a + b;
};
System.out.println(singleMultiple.test(20, 30));
}
}
可以感受到,使用Lambda表达式的基础语法去实现函数式接口时,其代码量并没有减少多少,所以需要了解更精简的Lambda表达式语法。
2.2、精简语法
Lambda表达式由参数列表和方法体组成,所以只好从这两部分着手简化,如下:
1、可以省略参数列表中的形参类型;
2、当只有一个形参时,可以省略参数列表的小括号;
3、当只有方法体的语句只有一条时,可以省略大括号;
4、当方法体的语句只有一条,而且是return语句时,可以省略return关键字;
三、方法引用
简单说明一下方法引用,如下:
实质:
Lambda表达式引用一个已经具体实现的方法来完成对函数式接口中抽象方法的实现。
前提:
被Lambda表达式引用的方法其参数列表和返回值类型必须和函数式接口中方法的参数列表和返回值类型一致。
3.1、成员方法引用
Lambda表达式引用一个成员方法来完成对函数式接口中抽象方法的实现,引用成员方法的语法,如下:
成员方法的隶属者::成员方法名
注释:
方法的隶属者,就是方法的调用者,静态方法的隶属者就是类;非静态方法的隶属者就是对象。
1)创建一个函数式接口,如下:
@FunctionalInterface
public interface Calculator {
int add(int num1, int num2);
}
2)使用Lambda表达式引用成员方法来完成对函数式接口中抽象方法的具体实现,如下:
public class TestDemo {
// 静态成员方法,其隶属者是当前类。
public static int add01(int a, int a) {
return a + b;
}
// 非静态成员方法,其隶属者是当前类对象。
public int add02(int a, int b) {
return a + b;
}
public static void main(String[] args) {
// "类名::静态成员方法名"
Calculator calculator01 = TestDemo::add01;
System.out.println(calcutor01.add(2, 3));
// "对象名::非静态成员方法名"
TestDemo demo = new TestDemo();
Calculator calculator02 = demo::add02;
System.out.println(calcutor02.add(2, 3));
}
}
3.2、构造方法引用
Lambda表达式引用一个构造方法来完成对函数式接口中抽象方法的实现。引用构造方法的语法,如下:
类名::new
注意:
类名::new,只是声明Lambda表达式引用某类的构造方法,具体引用哪种构造方法尚不知晓。
只有在执行函数式接口的抽象方法时,通过抽象方法的参数列表来确认引用该类的哪种构造方法。
1)创建一个实体类Person.java,如下:
public class Person {
private String name;
private Integer age;
public Person() {
System.out.println("正在执行Person类的无参构造方法……");
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
System.out.println("正在执行Person类的全参构造方法……");
}
}
2)创建两个函数式接口,如下:
public interface PersonCreator01 {
// 获取无参对象
Person getNoParamPerson();
}
public interface PersonCreator02 {
// 获取全参对象
Person getAllParamPerson(String name. Integer age);
}
3)使用Lambda引用具体的构造方法来完成对函数式接口中抽象方法的具体实现,如下:
public class TestDemo {
public static void main(String[] args) {
// 由抽象方法的参数列表可知,此时引用的是Person类的无参构造方法
PersonCreator01 creator01 = Person::new;
System.out.println(creator01.getNoParamPerson());
// 由抽象方法的参数列表可知,此时引用的是Person类的全参构造方法
PersonCreator02 creator02 = Person::new;
System.out.println(creator02.getAllParamPerson("张三", 23));
}
}