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. 不容易进行调试
相关推荐
摇滚侠2 小时前
基于 session 的登录认证方式,基于 token 的登录认证方式,对比
java·开发语言·intellij-idea
北国1372 小时前
【Java】多线程输出滞后/错误解决&&线程创建方式与原理
java·开发语言
假客套2 小时前
2026 JAVA 腾讯云人脸比对工具类,支持url或者base64进行比对
java·spring boot·腾讯云人脸比对
wfsm2 小时前
reactive streaming
java
Coder_Boy_2 小时前
【Java核心】JVM核心知识清单
java·开发语言·jvm
在坚持一下我可没意见2 小时前
ideaPool论坛系统测试报告
java·spring boot·功能测试·selenium·jmeter·mybatis·压力测试
wengqidaifeng2 小时前
数据结构(三)栈和队列(下)队列:程序世界的秩序之美
数据结构
程序员酥皮蛋2 小时前
hot 100 第二十三题 23.反转链表
数据结构·算法·leetcode·链表
像少年啦飞驰点、2 小时前
零基础入门 RabbitMQ:从消息队列是什么到 Spring Boot 实战收发消息
java·spring boot·微服务·消息队列·rabbitmq·异步编程