Lambda表达式是什么

Lambda 表达式:Java 8+ 的 "简洁函数式语法"

Lambda 表达式是 Java 8 引入的 核心函数式编程特性 ,本质是「匿名函数」------ 没有类名、方法名的简洁函数定义,可直接作为参数传递或赋值给变量,核心目的是 简化代码、减少冗余(如匿名内部类的模板代码),同时让代码更聚焦 "逻辑本身"。

一、为什么需要 Lambda 表达式?(对比匿名内部类)

在 Java 8 之前,若要使用「函数式接口」(只有一个抽象方法的接口),需通过匿名内部类实现,代码冗余且可读性差。Lambda 表达式可直接替代这一场景,大幅简化代码。

示例:线程创建(匿名内部类 vs Lambda)

1. 匿名内部类(Java 8 前)

java

复制代码
// 实现 Runnable 接口(函数式接口,仅 run() 一个抽象方法)
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("匿名内部类实现线程");
    }
}).start();
  • 问题:模板代码多(new Runnable()@Override、方法体框架),核心逻辑(System.out.println(...))被淹没。
2. Lambda 表达式(Java 8+)

java

复制代码
// Lambda 直接替代匿名内部类,只保留核心逻辑
new Thread(() -> System.out.println("Lambda 实现线程")).start();
  • 优势:去掉所有模板代码,直接聚焦 "线程要执行的逻辑",代码简洁直观。

二、Lambda 表达式的核心语法

Lambda 表达式的语法格式可概括为:(参数列表) -> { 方法体 }

1. 语法拆解

部分 说明
(参数列表) 对应函数式接口中抽象方法的参数:- 无参数时写 ();- 单参数可省略括号(如 s -> ...);- 多参数用逗号分隔(如 (a, b) -> ...);- 可省略参数类型(JVM 自动推断,如 (a, b) 等价于 (int a, int b))。
-> Lambda 运算符(箭头符号),分隔参数列表和方法体,意为 "将参数传递给逻辑"。
{ 方法体 } 对应抽象方法的实现逻辑:- 单条语句可省略大括号和 ;(如 () -> System.out.println(...));- 多条语句必须用大括号包裹,且需显式写 return(若有返回值)。

2. 常见语法变体(实战常用)

以「函数式接口 Comparator<Integer>」(排序逻辑)为例,展示不同语法写法:

java

复制代码
import java.util.Arrays;
import java.util.Comparator;

public class LambdaSyntax {
    public static void main(String[] args) {
        Integer[] arr = {3, 1, 2};

        // 1. 完整语法(多参数、显式类型、多条语句)
        Comparator<Integer> comp1 = (Integer a, Integer b) -> {
            System.out.println("比较 a=" + a + " 和 b=" + b);
            return a - b; // 有返回值需显式 return
        };
        Arrays.sort(arr, comp1);

        // 2. 简化1:省略参数类型(JVM 自动推断)
        Comparator<Integer> comp2 = (a, b) -> {
            return a - b;
        };

        // 3. 简化2:单条返回语句,省略大括号和 return
        Comparator<Integer> comp3 = (a, b) -> a - b;

        // 4. 最终简化(直接作为参数传递)
        Arrays.sort(arr, (a, b) -> a - b); // 最简洁写法
    }
}

三、Lambda 表达式的使用前提:函数式接口

Lambda 表达式 不能单独存在 ,必须绑定到一个「函数式接口」(Functional Interface)------ 即 只有一个抽象方法的接口(可含默认方法、静态方法)。

1. 核心特点

  • 接口上可加 @FunctionalInterface 注解(可选,但推荐,编译器会强制检查是否符合函数式接口规范);
  • 抽象方法的签名(参数类型、返回值类型)必须与 Lambda 表达式的语法匹配("函数签名一致")。

2. Java 内置的常用函数式接口(java.util.function 包)

Java 8 提供了大量现成的函数式接口,覆盖大部分开发场景,无需自定义:

接口名 抽象方法 功能描述 示例场景
Runnable void run() 无参数、无返回值 线程任务、异步回调
Consumer<T> void accept(T t) 接收一个参数 T,无返回值 遍历集合(如 forEach
Supplier<T> T get() 无参数,返回一个 T 类型值 生成对象、延迟加载
Function<T, R> R apply(T t) 接收 T 类型参数,返回 R 类型 数据转换(如 String→Integer)
Predicate<T> boolean test(T t) 接收 T 类型参数,返回布尔值 条件过滤(如集合筛选)
BiFunction<T,U,R> R apply(T t, U u) 接收 T、U 两个参数,返回 R 多参数转换(如 a+b→字符串)

3. 示例:使用内置函数式接口

java

复制代码
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Function;

public class BuiltInFunctionalInterface {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Lambda");
        list.add("Stream");

        // 1. Consumer<T>:遍历集合(无返回值,消费参数)
        list.forEach(s -> System.out.println(s)); // 输出所有元素

        // 2. Predicate<T>:筛选条件(返回布尔值)
        List<String> longStrList = filter(list, s -> s.length() > 4);
        System.out.println(longStrList); // 输出 [Lambda, Stream]

        // 3. Function<T, R>:数据转换(String→Integer)
        List<Integer> strLengthList = map(list, s -> s.length());
        System.out.println(strLengthList); // 输出 [4, 6, 6]
    }

    // 筛选集合:按 predicate 条件保留元素
    private static <T> List<T> filter(List<T> list, Predicate<T> predicate) {
        List<T> result = new ArrayList<>();
        for (T t : list) {
            if (predicate.test(t)) {
                result.add(t);
            }
        }
        return result;
    }

    // 转换集合:按 function 将 T 转为 R
    private static <T, R> List<R> map(List<T> list, Function<T, R> function) {
        List<R> result = new ArrayList<>();
        for (T t : list) {
            result.add(function.apply(t));
        }
        return result;
    }
}

四、Lambda 表达式的核心特性

1. 闭包特性:访问外部变量

Lambda 表达式可访问外部的局部变量或成员变量,但有约束:

  • 局部变量:必须是「最终变量(final)」或「effectively final(实际不可变,即声明后未重新赋值)」;
  • 成员变量:无约束(可修改)。

示例:

java

复制代码
public class LambdaClosure {
    private static String prefix = "Hello: "; // 成员变量(可修改)

    public static void main(String[] args) {
        String suffix = "!"; // 局部变量(effectively final,未重新赋值)
        // final String suffix = "!"; // 显式 final 也可以

        Consumer<String> consumer = s -> {
            prefix = "Hi: "; // 允许修改成员变量
            System.out.println(prefix + s + suffix); // 访问局部变量 suffix
        };

        consumer.accept("Lambda"); // 输出 Hi: Lambda!
    }
}

2. 类型推断

Lambda 表达式的参数类型、返回值类型无需显式声明,JVM 会根据「函数式接口的抽象方法签名」自动推断,简化代码。

示例:

java

复制代码
// Function<String, Integer> 接口,抽象方法是 Integer apply(String t)
Function<String, Integer> strToInt = s -> s.length(); 
// JVM 推断:s 是 String 类型,返回值是 Integer 类型(无需显式写 (String s) -> (int) s.length())

3. 与匿名内部类的区别

对比维度 Lambda 表达式 匿名内部类
适用场景 仅函数式接口(单抽象方法) 任意接口、抽象类
语法简洁度 极高(无模板代码) 冗余(需写类体、@Override)
this 指向 指向外部类的对象 指向匿名内部类自身实例
性能 更优(无额外类对象创建) 略差(创建匿名类实例)

五、Lambda 表达式的实战场景

Lambda 表达式最常用的场景是 配合 Stream API 进行集合操作(过滤、排序、转换、聚合),也可用于线程、回调函数等场景。

示例:Stream + Lambda 简化集合操作

java

复制代码
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LambdaStream {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("张三", 20, "男"),
            new Person("李四", 25, "男"),
            new Person("王五", 18, "女"),
            new Person("赵六", 30, "男")
        );

        // 需求:筛选 20 岁以上的男性 → 提取姓名 → 按年龄升序排序 → 转为列表
        List<String> result = people.stream()
            .filter(p -> p.getAge() > 20 && "男".equals(p.getGender())) // 过滤(Predicate)
            .sorted((p1, p2) -> p1.getAge() - p2.getAge()) // 排序(Comparator)
            .map(Person::getName) // 转换(Function,方法引用简化 Lambda)
            .collect(Collectors.toList()); // 聚合为列表

        System.out.println(result); // 输出 [李四, 赵六]
    }

    static class Person {
        private String name;
        private int age;
        private String gender;

        // 构造方法、getter 省略
        public Person(String name, int age, String gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }

        public String getName() { return name; }
        public int getAge() { return age; }
        public String getGender() { return gender; }
    }
}

总结

Lambda 表达式的核心价值是「简洁 + 聚焦逻辑」,关键要点:

  1. 本质是匿名函数,语法为 (参数) -> 方法体
  2. 必须绑定到函数式接口(单抽象方法接口);
  3. 常用 Java 内置函数式接口(Consumer/Predicate/Function 等);
  4. 常与 Stream API 配合,大幅简化集合操作;
  5. 支持闭包特性,可访问外部变量(局部变量需不可变)。

掌握 Lambda 表达式后,能显著提升代码简洁度和开发效率,是 Java 8+ 开发的必备技能。

相关推荐
牙牙要健康16 分钟前
【open3d】示例:自动计算点人脸点云模型面部朝向算法
人工智能·python·算法
她说..17 分钟前
Java AOP完全指南:从原理到实战(全套知识点+场景总结)
java·开发语言·spring·java-ee·springboot
Sammyyyyy17 分钟前
Rust性能调优:从劝退到真香
开发语言·后端·rust·servbay
r***869821 分钟前
Python中的简单爬虫
爬虫·python·信息可视化
Zfox_22 分钟前
【Go】异常处理、泛型和文件操作
开发语言·后端·golang
zhangyanfei0124 分钟前
谈谈 Golang 中的线程协程是如何管理栈内存的
开发语言·后端·golang
atregret29 分钟前
OSError: [WinError 1114] 动态链接库(DLL)初始化例程失败。Error loading ... c10.dll
人工智能·python
浪客川29 分钟前
高效日志分离器:一键筛选关键信息
开发语言·windows·c#
星竹晨L32 分钟前
C++红黑树:理论与实践相结合的平衡艺术
开发语言·数据结构·c++