一文彻底掌握Java中的Lambda表达式

 更新时间:2026年01月07日 10:11:09   作者:在地球迷路的怪兽  
Lambda表达式是Java 8引入的一项重要功能,它允许我们以更简洁和灵活的方式编写代码,这篇文章主要介绍了Java中Lambda表达式的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

为什么需要 Lambda 表达式?

Lambda表达式是Java函数式编程的核心概念之一。同时它也是一个相对难以理解的概念。

那么为什么需要它呢?

Lambda 表达式的出现是为了简化实现函数式接口 Functional Interface 的,什么又是函数式接口呢?

因此再讲函数式接口之前,先来回顾一下 interface 的概念与基本使用。

interface 接口

接口是用来定义一个协议或约定,它只声明方法但不提供方法的具体实现。

我们称这样的方法为抽象方法 Abstract Method 。

具体方法的实现是由实现这个接口的 class 来提供的:

这样一来将接口的声明与具体实现分开,业务中就只需要关心方法,而不需要关心具体的实现类,从而实现代码的解耦与模块化。

假如现在有一个需求,通过一个方法来发送多种不同类型的消息,比如既可以发送 Email 消息也可以发送 SMS 短信消息,这种场景就非常适合使用 Interface 来实现。

我们先定义一个消息发送的接口:

/**
 * @author TheSea
 * @description 消息接口
 * @createDate 2025/12/28
 */
public interface Message {
    void send();
}

接下来创建一个 Email 类来实现这个 Message 接口:

/**
 * @author TheSea
 * @description 邮件消息类
 * @createDate 2025/12/28
 */
public class Email implements Message{

    private String email;

    @Override
    public void send() {
        System.out.println("这是一份邮件消息.");
    }
}

再来创建一个 Sms 类来实现这个 Message 接口:

/**
 * @author TheSea
 * @description 短信消息类
 * @createDate 2025/12/28
 */
public class Sms implements Message{

    private String phone;

    @Override
    public void send() {
        System.out.println("这是一份手机短信消息.");
    }
}

现在我们来发送邮件消息,写一个方法用来负责统一发送消息:

	// 参数类型为接口,因为参数类型为 Message 接口类型,
    // 这就意味着不管传入的是 Email 还是 Sms 对象,
    // 它们的类都已经各自实现了 Message 接口的 send 方法
    // 所以 sendMsg 方法内部只需要执行 message 的 send 方法
    // 而不需要关心执行的到底是哪个对象的 send 方法
    // 免去了复杂的判断和切换,这就是面向接口编程的一个典型应用场景
    public static void sendMsg(Message message){
        message.send();
    }

现在尝试发送邮件消息:

public class Main {
    public static void main(String[] args) {
        //发送邮件消息
        Message emailMessage = new Email();
        sendMsg(emailMessage);
    }

    // 参数类型为接口,因为参数类型为 Message 接口类型,
    // 这就意味着不管传入的是 Email 还是 Sms 对象,
    // 它们的类都已经各自实现了 Message 接口的 send 方法
    // 所以 sendMsg 方法内部只需要执行 message 的 send 方法
    // 而不需要关心执行的到底是哪个对象的 send 方法
    // 免去了复杂的判断和切换,这就是面向接口编程的一个典型应用场景
    public static void sendMsg(Message message){
        message.send();
    }
}

再来尝试一下发送 Sms 消息:

public class Main {
    public static void main(String[] args) {
        //发送短信消息
        Message smsMessage = new Sms();
        sendMsg(smsMessage);
    }

    // 参数类型为接口,因为参数类型为 Message 接口类型,
    // 这就意味着不管传入的是 Email 还是 Sms 对象,
    // 它们的类都已经各自实现了 Message 接口的 send 方法
    // 所以 sendMsg 方法内部只需要执行 message 的 send 方法
    // 而不需要关心执行的到底是哪个对象的 send 方法
    // 免去了复杂的判断和切换,这就是面向接口编程的一个典型应用场景
    public static void sendMsg(Message message){
        message.send();
    }
}

到这里按照传统方法,我们已经正确的实现和使用了接口,应用场景也 OK。

问题的引入

但是我们会发现,要发送一条消息要经过好多个步骤,比如我们发送 Sms 消息。

我们需要先创建一个 Sms 类,然后去实现 Message 接口中的 send() 方法,然后再实例化一个 Sms 对象,再调用 send 发送消息,非常繁复。

而 Lambda 表达式的出现就可以帮助我们解决这个问题。

Lambda 表达式

Lambda 表达式可以提供一种简单快速的方式来实现上述接口,接口的抽象方法的具体实现直接在 Lambda 表达式里面定义即可,而不用像传统方法那样创建类然后实现接口的抽象方法、实例化对象最后调用方法,大大简化了代码的编写流程。

接下来用 Lambda 表达式重新实现一下刚才的例子。

public class Main {
    public static void main(String[] args) {
        // send()方法的实现:
        // public void send() {
        //     System.out.println("这是一份邮件消息.");
        // }

        // Lambda 表达式可以直接可以直接实现 Message 接口的 send 抽象方法,然后作为参数传给 sendMessage
        // () 代表的就是 send() 方法后面的括号,即参数列表
        // {} 大括号里面的内容就是 send() 方法的函数体
        sendMsg(() ->{
            System.out.println("这是一份邮件消息.");
        });
    }

    // 参数类型为接口,因为参数类型为 Message 接口类型,
    // 这就意味着不管传入的是 Email 还是 Sms 对象,
    // 它们的类都已经各自实现了 Message 接口的 send 方法
    // 所以 sendMsg 方法内部只需要执行 message 的 send 方法
    // 而不需要关心执行的到底是哪个对象的 send 方法
    // 免去了复杂的判断和切换,这就是面向接口编程的一个典型应用场景
    public static void sendMsg(Message message){
        message.send();
    }
}

上面这条 Lambda 表达式就等效于之前用传统方法实现的 Email 实例对象。

如果 Lambda 的函数体里只包含一个表达式,那么可以省略大括号进行简写:

sendMsg(() -> System.out.println("这是一份邮件消息."));

如果 Lambda 表达式包含多条语句或者需要明确的流程控制,那么就必须要使用大括号。

目前的例子中抽象方法并没有参数,现在假设抽象方法有一个参数 name:

public interface Message {
    void send(String name);
}

那么 Lambda 表达式中就需要这么定义:

public class Main {
    public static void main(String[] args) {
        sendMsg((name) -> System.out.println(name + ": 这是一份邮件消息."));
    }

    public static void sendMsg(Message message){
        message.send("TheSea");
    }
}

注意上面的 参数名 是形参,可以随便写,不一定要和接口中声明的一样,比如这样写也是一样的效果:

sendMsg((nameInLambda) -> System.out.println(nameInLambda + ": 这是一份邮件消息."));

如果参数只有一个的话,Lambda 表达式的参数列表的小括号是可以去掉的:

sendMsg(name -> System.out.println(name + ": 这是一份邮件消息."));

那么如果有多个参数呢?那就按顺序书写,然后中间用逗号分隔即可,注意必须要带上小括号嗷:

public interface Message {
    void send(String name, int age);
}
public class Main {
    public static void main(String[] args) {
        sendMsg((name, age) -> System.out.println(name + ": 您" + age + "岁了,这是一份邮件消息."));
    }

    public static void sendMsg(Message message) {
        message.send("TheSea", 18);
    }
}

注意一定要参数的声明顺序书写编译器才能对上号,否则的话会出现下面的荒唐局面:

public class Main {
    public static void main(String[] args) {
        sendMsg((age, name) -> System.out.println(name + ": 您" + age + "岁了,这是一份邮件消息."));
    }

    public static void sendMsg(Message message) {
        message.send("TheSea", 18);
    }
}

以上示例的抽象方法都没有返回值,我们来看一下有返回值的情况:

public interface Message {
    String send(String name, int age);
}

此时我们之前的 Lambda 表达式就会报错:

因为我们需要有返回值:

可以看到,如果函数体只有一条返回语句,像上面这样写会报错,原因是如果只有一条返回语句的话,return 关键字是不需要存在的,可以简化成下面这样:

public class Main {
    public static void main(String[] args) {
        sendMsg((age, name) -> "Lambda 表达式的返回值");
    }

    public static void sendMsg(Message message) {
       String res =  message.send("TheSea", 18);
        System.out.println(res);
    }
}

现在把参数应用进去,当函数体有多条表达式的时候,需要用大括号包围:

public class Main {
    public static void main(String[] args) {
        sendMsg((name, age) -> {
            System.out.println(name + ": 您" + age + "岁了,这是一份邮件消息.");
            return "Lambda 表达式的返回值";
        });
    }

    public static void sendMsg(Message message) {
       String res =  message.send("TheSea", 18);
        System.out.println(res);
    }
}

另外如果现在我们想改另外一种发送方式,比如使用 Sms,那么我们现在也不需要再新建一个 Sms 类来实现接口了,直接修改 Lambda 表达式的函数体就可以:

public class Main {
    public static void main(String[] args) {
        sendMsg((name, age) -> {
            System.out.println(name + ": 您" + age + "岁了,这是一份短信消息.");
            return "Lambda 表达式的返回值";
        });
    }

    public static void sendMsg(Message message) {
       String res =  message.send("TheSea", 18);
        System.out.println(res);
    }
}

Lambda 表达式也可以像普通对象那样赋值给变量,如下:

public class Main {
    public static void main(String[] args) {
        Message lambda = (name, age) -> {
            System.out.println(name + ": 您" + age + "岁了,这是一份短信消息.");
            return "Lambda 表达式的返回值";
        };
        
        sendMsg(lambda);
    }

    public static void sendMsg(Message message) {
       String res =  message.send("TheSea", 18);
        System.out.println(res);
    }
}

综上所述,Lambda 让我们实现接口抽象方法的整个过程变得非常简单。

那么 Lambda 表达式是不是可以应用在任何形式的 interface 上呢?

当然不行!

Lambda 表达式只能应用于有且只有一个抽象方法的接口上,我们称这样的接口为函数式接口。

那为什么Java要这么定义呢?

因为一个接口如果有多个抽象方法的话,那么在使用 Lambda 表达式的时候 Java 将无法确定 Lambda 试图实现哪一个抽象方法,而当只有一个抽象方法的时候对于 Java 来说意图就非常明确。

因此只有函数式接口才可以使用 Lambda 表达式。

另外,我们可以使用 @FunctionalInterface 注解来标识该接口为一个函数式接口:

@FunctionalInterface
public interface Message {
    String send(String name, int age);
}

这个注解是可选的,因为函数式接口定义的本身并不依赖于这个注解,即便不标注但只要符合函数式接口的定义条件,Java自动就会把它当成是函数式接口。

不过工程开发中我们还是建议使用该注解来进行标识,这样的话如果出现多余一个抽象方法或者是没有抽象方法的时候就会编译报错,同时也会提供一个非常好的语义方便工程师更好的理解该接口的设计意图。

总结

Lambda 表达式归根到底是一种语法糖,用于简化函数式接口的实现。

在 Java 的函数式编程中起到了关键的作用,Java 标准库中也包含了非常多的内置的函数式接口,比如 Predicate、Function、Consumer、Supplier 等等,经常与 Stream API 结合使用。

所以掌握 Lambda 表达式是非常重要的。

到此这篇关于Java中Lambda表达式的文章就介绍到这了,更多相关Java中Lambda表达式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现连接mysql数据库单元测试查询数据的实例代码

    java实现连接mysql数据库单元测试查询数据的实例代码

    下面小编就为大家带来一篇java实现连接mysql数据库单元测试查询数据的实例代码。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • SpringBoot整合junit与Mybatis流程详解

    SpringBoot整合junit与Mybatis流程详解

    这篇文章主要介绍了SpringBoot整合第三方技术,包括整合Junit、整合Mybatis,本文通过实例代码相结合给大家介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • Spring Boot使用模板引擎JSP实例解析

    Spring Boot使用模板引擎JSP实例解析

    这篇文章主要介绍了Spring Boot使用模板引擎JSP实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • MyBatis方法重载的陷阱及解决方案

    MyBatis方法重载的陷阱及解决方案

    在使用 MyBatis 进行开发时,尤其是使用注解模式(如 @Select、@Insert 等)时,开发者常常会遇到这样一个问题:为什么我的方法重载不能正常工作?这篇文章将深入探讨 MyBatis 的这个特性及如何规避相关的坑,需要的朋友可以参考下
    2024-09-09
  • Java并发编程总结——慎用CAS详解

    Java并发编程总结——慎用CAS详解

    下面小编就为大家带来一篇Java并发编程总结——慎用CAS详解。小编觉得挺不错的, 现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • Java面试必考之如何在项目中优雅的抛出异常

    Java面试必考之如何在项目中优雅的抛出异常

    这篇文章主要为大家详细介绍了Java中的几种异常关键字和异常类相关知识,本文比较适合刚入坑Java的小白以及准备秋招的大佬阅读,需要的可以收藏一下
    2023-06-06
  • springboot2中session超时,退到登录页面方式

    springboot2中session超时,退到登录页面方式

    这篇文章主要介绍了springboot2中session超时,退到登录页面方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java构造方法实例详解(动力节点java学院整理)

    Java构造方法实例详解(动力节点java学院整理)

    其实java构造方法很简单,下面通过示例给大家分享java构造方法,非常不错,具有参考借鉴价值,需要的朋友参考下
    2017-04-04
  • springboot中@RequestParam和@PathVariable区别

    springboot中@RequestParam和@PathVariable区别

    本文主要介绍了springboot中@RequestParam和@PathVariable区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-07-07
  • Java详解多线程协作作业之信号同步

    Java详解多线程协作作业之信号同步

    信号量同步是指在不同线程之间,通过传递同步信号量来协调线程执行的先后次序。CountDownLatch是基于时间维度的Semaphore则是基于信号维度的
    2022-05-05

最新评论