什么是Java中的Lambda表达式
Lambda表达式是Java函数式编程的概念之一。对于这个概念在第一次接触和使用的时候会比较难以理解,他的作用就是为了简化实现函数接口,是一个非常抽象的概念。
- 接口(interfase):用来定义一个协议或约定,他只声明方法,但不提供方法的具体实现,我们称之为抽象方法(Abstract Method),方法的具体实现,是由实现这个接口的实现类来提供的。这样做的好处就是,在业务中我们只需要关心方法的视实现,而不需要关心具体的实现类,从而实现代码的解耦和模块化。
案例实现
比如我们这里可以通过一个经典的案例来实现:比如此时我准备了一个发送信息的业务,他可以发送Email,或者是sms短信,那么首先,我就需要一个信息接口,接口中还应该包含一个发送信息的方法定义:
public interface massage {
void send();
}
Copy
那么接下来,我们还需要让具体发送信息的类去实现它,比如如果我想要发送的是一个Email消息:
public class EmailSend implements massage{
public String EmailAddress;
@Override
public void send() {
System.out.println("Send a Email……");
}
}
Copy
那么如果我想要发送的是一个SMS短信的话,就需要使用另一个类来实现它:
public class SmsSend implements massage{
public String PhoneNum;
@Override
public void send() {
System.out.println("Send a SMS……");
}
}
Copy
然后,这样做的好处是什么?以及我们为什么要这么做?如果我不用实现这个接口,我依然可以单独创建两个类去实现各自的功能,那么我们就在实际业务中去使用一下然后去体会一下他们之间的差别。
那么首先,如果我想要发送一条消息的时候,我们需要再实现业务的主类中创建一个发送消息的方法,比如这样:
public class sendMain {
public static void main(String[] args) {
}
static void sendMassage(massage mas){
mas.send();
}
}
Copy
那么我们在做了这一步之后,我们只需要在调用的时候,调用这个sendMassage方法,而在这个方法中只做一件事就是根据传入的对象调用对象的send方法,而由于传入的对象是一个接口,所以任何实现了这个接口的实体类对象都可以被传进来并调用send方法,区别就是根据实现类的不同,方法的效果也会不同。这个就叫做多态啊。
比如此时,如果我想要发送一个Email消息:
public class sendMain {
public static void main(String[] args) {
massage email = new EmailSend();
sendMassage(email);
}
static void sendMassage(massage mas){
mas.send();
}
}
Copy
运行效果是这样的:
那么如上所示,我们创建了一个email接口类型,但是创建的对象是EmailSend类,所以当我们将这个对象传递进sendMassage方法里面的时候,他实际执行的方法就是EmailSend类中实现的send方法,这是多态的基本使用。那么如果此时我想换成发送SMS消息的话,就需要将之前的EmailSend对象换一下:
public class sendMain {
public static void main(String[] args) {
massage sms = new SmsSend();
sendMassage(sms);
}
static void sendMassage(massage mas){
mas.send();
}
}
Copy
同理,只需要更换执行接口中方法的对象,就可以实现切换不同的执行效果,那么执行效果的变了:
lambda的优点
那么在之前的案例中,我们看到了如果要实现上面的案例,就需要首先定义一个接口,然后使用实现类去实现接口中的方法,写出具体的实现,然后创建实现类的对象,之后调用方法,那么整个的过程下来是非常的繁琐的,那么lambda表达式的出现就简化了我们做这一部分的代码量,他可以直接把具体的实现方法写在表达式中。
比如,如果我想要实现一下刚才那一段发送Email的代码,通过lambda表达式的方式就是如下所示:
public class sendMain {
public static void main(String[] args) {
sendMassage(() -> {
System.out.println("send an Email");
});
}
static void sendMassage(massage mas){
mas.send();
}
}
Copy
那么lambda表达式的基本实现方法,就是:
(参数列表) -> {lambda函数体}
Copy
通过这种方式就可以实现一个最简单的lambda表达式。并且替换的方式也很简单,只需要将lambda中的函数体内容修改一下,就可以得到另一种实现效果。并且lambda表达式也可以赋值给某一个变量:
public class sendMain {
public static void main(String[] args) {
massage Massage = () -> {
System.out.println("send an Email");
};
sendMassage(Massage);
}
static void sendMassage(massage mas){
mas.send();
}
}
Copy
那么如果想要传递参数的话,比如此时我们在接口的方法中增加一个参数:
public interface massage {
void send(String name);
}
Copy
那么对应的,你的lambda中也需要添加一个参数:
public class sendMain {
public static void main(String[] args) {
massage Massage = (name) -> {
System.out.println("send an Email"+name);
};
sendMassage(Massage);
}
static void sendMassage(massage mas){
mas.send("Tom");
}
}
Copy
注意此时,我们添加参数的位置是在lambda中,那么我们传递参数值的位置,是在调用方法的位置,也就是发送消息的时候,这个真正调用方法实现业务的地方。
lambda的简写
对于lambd来说,有一些简写的语法,比如当参数只有一个的时候,参数列表的小括号可以省略,当函数体中的语句只有一个的时候,函数体的大括号也可以省略,当然因为我自己不喜欢这些简写的语法,我就给出一个简单的实例,有兴趣的可以深入地学习一下。
public class sendMain {
public static void main(String[] args) {
sendMassage(name -> System.out.println("send an Email"+name));
}
static void sendMassage(massage mas){
mas.send("Tom");
}
}
Copy
lambda表达式的限制
lambda表达式是不能用在任意的表达式中的,他在使用上有一些限制,其中包括
- 只能用于有且只有一个抽象方法的接口中,这种有且只有一个抽象方法的接口为函数式接口
- 当一个接口中有多个抽象方法的时候,lambda表达式就无法确定你想要实现哪一个接口
- 只有函数式接口才能使用lambda表达式
为了防止我们在错误的接口中使用lambda,我们可以在方法中声明一个注解叫做**@FunctionInterface**
@FunctionalInterface
public interface massage {
void send(String name);
}
Copy
在开发过程中,函数式接口的定义本身并不依赖于这个注解,而是说当接口使用了这个注解的时候,如果里面的抽象方法超过一个,则会直接在接口中报错,减轻我们后续DeBUG的工作量。
总结
Lambda归根到底是一种语法糖,它的出现是为了简化函数式接口的实现,在Java的函数式编程中起到了关键的作用,Java标准库当中也内置了很多的函数式接口,比如Predicate,Function,Consumer,Supplier等等。掌握Lambda是很重要的。