java数据结构当中的《Lambda表达式》

一、Lambda 的核心概念

Lambda 表达式可以理解为:一段可以传递的代码(将代码像数据一样传递) ,它的本质是简化后的匿名内部类,但只适用于特定场景 ------ 实现函数式接口(只有一个抽象方法的接口)。

你可以把 Lambda 看作 "语法糖",目的是减少冗余代码,让逻辑更聚焦。比如原本需要写好几行的匿名内部类,用 Lambda 一行就能搞定。

1.1 Lambda表达式的语法

基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

Lambda表达式由三部分组成:

  1. paramaters :类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明
    也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
  2. ->:可理解为"被用于"的意思
  3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不返回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不返回。
java 复制代码
// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

1.2 函数式接口

要了解Lambda表达式,首先需要了解什么是函数式接口,函数式接口定义:一个接口有且只有一个抽象方法 。

注意:

  1. 如果一个接口只有一个抽象方法,那么该接口就是一个函数式接口
  2. 如果我们在某个接口上声明了 @FunctionalInterface 注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的。所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解。加上就会自动进行检测的。
    定义方式:
java 复制代码
@FunctionalInterface
interface NoParameterNoReturn {
//注意:只能有一个方法
void test();
}

但是这种方式也是可以的:

java 复制代码
@FunctionalInterface
interface NoParameterNoReturn {
void test();
default void test2() {
System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");
}
}

二、Lambda 的基础使用(对比匿名内部类)

先看一个经典场景:用Runnable接口创建线程,对比传统写法和 Lambda 写法。

1. 传统匿名内部类写法

java 复制代码
public class LambdaBasic {
    public static void main(String[] args) {
        // 传统方式:匿名内部类实现Runnable接口
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() { // Runnable只有一个抽象方法run(),符合函数式接口
                System.out.println("传统方式:线程执行");
            }
        });
        t1.start();
    }
}

2. Lambda 简化写法

java 复制代码
public class LambdaBasic {
    public static void main(String[] args) {
        // Lambda写法:省略接口名、方法名,只保留参数和逻辑
        Thread t2 = new Thread(() -> System.out.println("Lambda方式:线程执行"));
        t2.start();

        // 更复杂的Lambda示例(带参数+多行代码)
        Thread t3 = new Thread(() -> {
            String msg = "多行代码的Lambda";
            System.out.println(msg);
        });
        t3.start();
    }
}

三、Lambda 的核心适用场景:集合操作(Stream API)

Lambda 最常用的场景是配合 Java 8 的Stream API 操作集合(List/Set/Map),替代传统的 for 循环,让代码更简洁、易读。

示例:操作 List 集合

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

public class LambdaStreamDemo {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("orange");
        fruits.add("grape");

        // 场景1:遍历集合(替代for-each)
        System.out.println("遍历集合:");
        fruits.forEach(fruit -> System.out.println(fruit)); // 单行Lambda

        // 场景2:过滤元素(筛选长度>5的水果)
        List<String> longNameFruits = fruits.stream()
                .filter(fruit -> fruit.length() > 5) // Lambda作为过滤条件
                .collect(Collectors.toList());
        System.out.println("\n长度>5的水果:" + longNameFruits); // 输出:[banana, orange]

        // 场景3:映射转换(把所有水果转成大写)
        List<String> upperFruits = fruits.stream()
                .map(fruit -> fruit.toUpperCase()) // Lambda作为转换逻辑
                .collect(Collectors.toList());
        System.out.println("\n大写水果名:" + upperFruits); // 输出:[APPLE, BANANA, ORANGE, GRAPE]

        // 场景4:聚合操作(统计水果名总长度)
        int totalLength = fruits.stream()
                .mapToInt(fruit -> fruit.length()) // 转换为长度的int流
                .sum(); // 求和
        System.out.println("\n水果名总长度:" + totalLength); // 输出:20
    }
}

四、自定义函数式接口(理解 Lambda 的本质)

Lambda 必须配合函数式接口使用,你也可以自定义函数式接口(@FunctionalInterface注解标记,编译器会检查是否只有一个抽象方法)。
示例:自定义函数式接口

java 复制代码
// 自定义函数式接口:计算两个数的操作
@FunctionalInterface // 注解可选,但推荐加,用于校验
interface Calculate {
    int operate(int a, int b); // 只有一个抽象方法
}

public class CustomFunctionalInterface {
    public static void main(String[] args) {
        // 用Lambda实现加法
        Calculate add = (a, b) -> a + b;
        System.out.println("10+20=" + add.operate(10, 20)); // 输出:30

        // 用Lambda实现乘法
        Calculate multiply = (a, b) -> a * b;
        System.out.println("10*20=" + multiply.operate(10, 20)); // 输出:200

        // 多行代码的Lambda(比如减法,加日志)
        Calculate subtract = (a, b) -> {
            System.out.println("执行减法操作:" + a + "-" + b);
            return a - b; // 多行代码必须加{}和return
        };
        System.out.println("10-20=" + subtract.operate(10, 20)); // 输出:-10
    }
}

Lambda在集合当中的使用

对应的接口 新增的方法
Collection removeIf() spliterator() stream() parallelStream() forEach()
List replaceAll() sort()
Map getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent()computeIfPresent() compute() merge()

以上方法的作用可自行查看我们发的帮助手册。我们这里会示例一些方法的使用。注意:Collection的forEach()方

法是从接口 java.lang.Iterable 拿过来的。

五、Lambda 的关键注意事项

  1. 变量捕获 :Lambda中可以使用外部的局部变量,但该变量必须是final或"事实上的final"(即没有被重新赋
    值);
java 复制代码
int num = 10; // 事实上的final(没有重新赋值)
Calculate addNum = (a, b) -> a + b + num; // 合法
// num = 20; // 报错:Lambda引用的局部变量不能重新赋值

2.适用范围 :仅能简化函数式接口的实现,不能用于普通类/多抽象方法的接口;

3.可读性:Lambda适合短逻辑,复杂逻辑(超过3行)建议抽成普通方法,避免Lambda嵌套导致代码难懂。

总结

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点

  1. 代码简洁,开发迅速
  2. 方便函数式编程
  3. 非常容易进行并行计算
  4. Java 引入 Lambda,改善了集合操作
    缺点
  5. 代码可读性变差
  6. 在非并行计算中,很多计算未必有传统的 for 性能要高
  7. 不容易进行调试
相关推荐
骇客野人几秒前
SpringBoot电商购物车、结算、下单、库存方案设计与落地实施步骤
java·spring boot·后端
asdzx678 分钟前
Python 实现 PDF 文本查找与高亮标注
开发语言·python·pdf
zander25811 分钟前
LeetCode 1143. 最长公共子序列
开发语言·python·算法
哪 吒20 分钟前
华为OD机试 - 云服务安全策略最优选择 - 深度优先搜索DFS(Java 新系统 200分)
java·华为od·深度优先
拒绝内耗。22 分钟前
程序员学架构(一):一张图看懂 Java 后端架构:一个请求怎样从手机到数据库?
java·智能手机·架构
棣廷23 分钟前
初识Python面向对象
java·开发语言
用户31268748772028 分钟前
ThreadLocal 到底会不会内存泄漏?源码级拆解 + 线程池陷阱
java
珍珠先生32 分钟前
P11 · MySQL 驱动版本过旧:Client does not support authentication protocol
java
~木雨40 分钟前
Java 并发编程架构全景:并发层的五域设计 —— 线程模型、线程池隔离、并发安全到问题治理(全体系汇总)
java·安全·架构·线程池·并发编程·高并发架构
轩情吖1 小时前
Python基础知识点完整总结
python·字符串·编程语言·函数·列表·元组·字典