Lambda表达式介绍
Lambda表达式是Java函数式编程的重要概念之一。它被用来简化实现函数式接口 (Functional Interface) 的,在进入Lambda的介绍前我们先来回顾一下Interface。
interface接口的基本概念
接口使用来定义一个约定或者说是一种协议,他只提供方法的声明,不提供方法的具体实现,我们还称这样的方法为抽象方法(Abstract Method),具体方法的实现是由实现这个接口的类来提供的。这样将方法的声明与实现分开,业务场景中只需要关心方法的定义,而不需要关心具体的实现,从而实现代码的解耦与模块化。我们来举一个简单的例子:
我们先在包下创建一个Massage接口(接口中定义一个send方法)与两个实现Message接口的实现类并实现send方法,和一个主类。分别如下所示:
//Message接口
public interface Message {
void send();
}
//实现类 Email
public class Email implements Message{
private String email;
public Email(){
}
@Override
public void send() {
System.out.println("This is a email");
}
}
//实现类 PhoneNumber
public class PhoneNumber implements Message{
private String phoneNumber;
public PhoneNumber()
{
}
@Override
public void send() {
System.out.println("This is a phoneNumber");
}
}
现有一个需求:通过一个方法来发送不同的消息
常规方法实现一定是写一个方法来接收不同的实现类的实例,再调用实现的方法,如下所示:
public class Main {
public static void main(String[] args) {
Email email = new Email();
//PhoneNumber phoneNumber = new PhoneNumber();
sendMessage(email);
}
static void sendMessage(Message message)
{
message.send();
}
}
为什么要引入Lambda表达式
上面的例子中,虽然只是一个方法,但是想要实现它却要经历这么多步骤,未免太麻烦了~
于是Lambda表达式的出现很好的解决了这个问题,如下所示:
public class Main {
public static void main(String[] args) {
sendMessage(()->{
System.out.println("This is a Lambda Email");
});
}
static void sendMessage(Message message)
{
message.send();
}
}
我们不再需要经历实现类的步骤,直接通过Lambda来实现想要的操作,大大简化了代码。
Lambda表达式的语法
1.Lambda表达式的语法为:括号(Parentheses)+连字号(Hyphen)+箭头(Arrow)+大括号(Curly Braces)。Lambda表达式中的括号就是我们一开始写的接口实现类中实现方法的括号,大括号中的就是我们具体要实现的函数体
2.如果Lambda表达式函数体中只包含一个表达式,那么大括号可省略。
public class Main {
public static void main(String[] args) {
sendMessage(()->
System.out.println("This is a Lambda Email"));
}
static void sendMessage(Message message)
{
message.send();
}
}
3.如果抽象方法中有一个参数,那么对应的,Lambda表达式中也应该有一个参数:
public interface Message {
void send(String name);
}
public class Main {
public static void main(String[] args) {
sendMessage((name)->
System.out.println("This is a Email to "+name));
}
static void sendMessage(Message message)
{
message.send("Lin");
}
}
如果只有一个参数,那么类似大括号,也可以将括号去掉:
public class Main {
public static void main(String[] args) {
sendMessage(name-> System.out.println("This is a Email to "+name));
}
static void sendMessage(Message message)
{
message.send("Lin");
}
}
4.如果抽象方法中有返回值,那么对应的,Lambda表达式中也应该有返回值:
public interface Message {
String send(String name);
}
public class Main {
public static void main(String[] args) {
sendMessage((name)-> {
System.out.println("This is a Email to "+name);
return "Success";
});
}
static void sendMessage(Message message)
{
System.out.println(message.send("Lin"));
}
}
至此,我们再来会看文章一开始的业务,通过一个方法发送不同的信息,我们写了两个实现类Email 和 PhoneNumber 最初我们想要使用PhoneNumber中的实现方法的话就需要new一个PhoneNumber实例 。当我们使用Lambda表达式时,就仅仅需要改一下函数体就行了:
public class Main {
public static void main(String[] args) {
sendMessage((name)-> {
System.out.println("This is a PhoneNumber to "+name);
return "Success";
});
}
static void sendMessage(Message message)
{
System.out.println(message.send("Lin"));
}
}
到现在应该可以发现,Lambda表达式让过程变得非常简洁和灵活,不再像传统方式那样需要去写实现类,然后再实例化对象等一系列操作。
函数式接口与Lambda表达式
如果你是第一次了解Lambda表达式那么你一定会感到好奇,Lambda表达式是不是可以用在任意的Interface上呢?它实现的机制又是什么?
事实上,Lambda表达式的使用是有限制的,它只能用于有且只有一个抽象方法的接口上,我们称这样的接口为函数式接口(Functional Interface)。其实这样的限制也很好理解,因为如果一个接口有多个抽象方法的话,再我们使用Lambda表达式时,Java将无法确定我们到底要实现的是哪一个抽象方法,当只有一个抽象方法时就不会出现这样的矛盾。换言之只有函数式接口才可以使用Lambda表达式。再我们文章开头例子中的Message接口中只有一给send()抽象方法,所以Message是一个函数式接口。
如果我们强行在有多个抽象方法的接口上使用Lambda表达式就会出现以下的报错:
此外还有一些技巧:
如果你在开发中就是认定一个接口它就是函数式接口,那么我们可以在接口上方加入
@FunctionalInterface 注解来表示这个接口为函数式接口。虽然说即使不标注这个注解,Java任然会将只有一个抽象方法的接口认定为函数式接口,但是加上注解也会带来一些益处,例如当我们在加上@FunctionalInterface注解的接口上写了多余的抽象函数,那么会直接爆红,如下图所示:
此外加上注解也能让其他人能够知道你对这个接口的设计意图。
最后,Lambda表达式归根结底只是一种语法糖,用于简化函数式接口的实现,在Java的函数式编程中起到了关键的作用。Java的标准库中也包含了许多内置的函数式接口,例如Predicate、Function、Consumer,Supplier等,经常与Stream API(点击可进入文章StreamAPI)一起使用。