欢迎光临
我们一直在努力

超新手的Lambda教程

一、Lambda是什么?

Lambda表达式是Java8推出的语法糖,用于极简简化【函数式接口】的匿名内部类代码。

传统匿名内部类代码冗余、模板代码多,Lambda可以去掉冗余格式,只保留参数 + 核心逻辑,也是 Stream流、函数式编程的底层基础。

二、必备前提:函数式接口

1. 定义

满足以下条件的接口,就是函数式接口:

有且仅有一个抽象方法(可以有多个默认方法、静态方法)

2. 专属注解

@FunctionalInterface

加在接口上,用于强制校验接口是否为函数式接口,编译报错提示,规范代码。

3. 自定义函数式接口示例

@FunctionalInterface
interface MyInterface {
// 1个抽象方法 *必须唯一
void test();

// 默认方法:随便写,不算抽象方法
default void demo1(){}
default void demo2(){}

// 静态方法:随便写,不算抽象方法
static void static1(){}
static void static2(){}
}

三、Lambda标准语法 & 四种简化规则

1. 标准完整语法

(参数列表) -> { 方法体逻辑 }

  • (参数列表):对应抽象方法的参数

  • ->:Lambda固定箭头符号,连接参数和方法体

  • {}:方法执行的核心代码

2.四层极简简化规则

所有简化可叠加使用,最终代码极度精简

  • 参数类型可省略:编译器可自动推断参数类型,无需手动声明

  • 单个参数可省略小括号:参数只有一个时,() 可以不写

  • 单行方法体可省略大括号:方法体只有一行代码,无需 {} 包裹

  • 单行返回可省略return:唯一一行代码是return返回值时,可省略return和{}

  • 四、Lambda的三种调用方式

    方式一:先定义变量,再调用

    逻辑:把Lambda表达式赋值给接口变量 → 再调用接口的抽象方法

    特点:直观、新手友好、可复用

    @FunctionalInterface
    interface Study {
    void learn(String subject);
    }

    // 1. 定义Lambda,赋值给接口变量
    Study s3 = sub -> System.out.println("正在学习:" + sub);
    // 2. 调用接口方法,执行Lambda逻辑
    s3.learn("Lambda表达式");

    执行顺序:先存逻辑 → 后执行逻辑

    方式二:匿名对象直接传(不用接收变量)

    逻辑:不需要定义变量,直接把Lambda当作方法参数传入,用完即走

    特点:代码更短、一次性使用、Stream底层全是这种写法

    @FunctionalInterface
    interface Study {
    void learn(String subject);
    }

    // 写一个方法,接收函数式接口参数
    public static void test(Study study){
    study.learn("直接传入的Lambda");
    }

    public static void main(String[] args) {
    // 直接把Lambda传进去,不定义变量
    test(sub -> System.out.println("正在学习:" + sub));
    }

    //输出:
    //正在学习:直接传入的Lambda

    核心理解:Lambda本质就是一段可传递的代码逻辑,可以直接当参数传输

    方式三:最简实战(Stream经典写法)

    这是你之后写代码用得最多的方式,本质就是方式二的进阶版

    List<String> list = Arrays.asList("Java","MySQL","Lambda");

    // 直接传入Lambda,无变量、无多余代码
    list.stream().forEach(str -> System.out.println("学习:" + str));

    原理:forEach方法接收Consumer函数式接口,直接传入Lambda实现逻辑

    五、Java内置四大核心函数式接口

    开发、Stream流高频使用,无需自定义接口,直接调用

    1. Consumer< T > 消费型接口

    特点:有参、无返回值,用于消费、处理数据

    常用场景:forEach遍历数据

    Consumer<String> consumer = str -> System.out.println("输出:" + str);
    consumer.accept("测试数据");

    2. Supplier< T > 供给型接口

    特点:无参、有返回值,用于生产、获取数据

    Supplier<Integer> supplier = () -> (int)(Math.random()*100);
    System.out.println("随机数:" + supplier.get());

    3. Function<T,R> 函数型接口

    特点:有参、有返回值,用于数据转换、类型映射

    常用场景:Stream map字段提取、数据转换

    Function<String,Integer> function = str -> str.length();
    System.out.println("字符串长度:" + function.apply("Lambda"));

    4. Predicate< T > 断言型接口

    特点:有参、返回布尔值,用于条件判断、数据筛选

    常用场景:Stream filter过滤数据

    Predicate<Integer> predicate = num -> num > 10;
    System.out.println(predicate.test(15)); // true
    System.out.println(predicate.test(5)); // false

    六、Lambda终极简化:方法引用

    当Lambda方法体仅调用一个已有方法,无额外逻辑,可使用方法引用进一步简化

    // 普通Lambda写法
    list.stream().forEach(s -> System.out.println(s));

    // 方法引用最简写法
    list.stream().forEach(System.out::println);

    七、Lambda核心禁忌与注意事项

    Lambda表达式不是独立代码块,有严格的使用限制

    1. 仅限函数式接口使用(硬性前提)

    Lambda的核心作用是简化单个抽象方法的函数式接口,若接口包含两个及以上抽象方法,无法使用Lambda表达式,编译器直接报错。

    原理:Lambda无法精准匹配多个抽象方法,不知道需要重写哪一个方法。

    2. 外部局部变量隐式Final规则(超级重点)

    一句话大白话结论:Lambda 只能读取【不变的外部局部变量】,不能读取被改过的变量

    详细规则:

    • Lambda 内部可以访问、读取 方法中的局部变量

    • 但是!这个局部变量 必须是没被修改过的(Java隐式认定为 final)

    • 只要你对外部局部变量做二次赋值,Lambda 直接报错

    通俗理解:

    Lambda 是延迟执行的代码,Java怕你外面改了变量,Lambda里面的值混乱,所以强制规定:给Lambda用的局部变量,必须固定不变。

    正确示例(能运行):变量没改过

    public static void main(String[] args) {
    // 只赋值一次,没修改,隐式final
    String info = "我是固定数据";

    // Lambda可以正常使用
    test(() -> System.out.println(info));
    }

    错误示例(直接报错):变量被修改了

    public static void main(String[] args) {
    String info = "我是固定数据";
    // 二次修改!破坏隐式final规则
    info = "被修改了";

    // 报错!Lambda不能用被修改的局部变量
    test(() -> System.out.println(info));
    }

    3. 内部不支持break、continue关键字

    Lambda属于独立的函数式代码块,不属于循环体内部,无法使用循环跳转关键字 break、continue,强行编写会直接报错。

    如需终止遍历、跳过元素,需使用Stream流的 filter、limit 等专属方法实现。

    4. 无法直接抛出受检异常

    Lambda表达式不允许直接抛出编译期受检异常(Exception、IOException等),如果代码逻辑存在异常风险,必须手动 try-catch 捕获处理,不能直接throws抛出。

    5. 无独立作用域,this指向特殊

    Lambda没有自己的局部作用域,内部的 this、super 均指向外部所属类对象,而非Lambda自身,不存在匿名内部类的this重写歧义,这是Lambda与匿名内部类的核心区别之一。

    6. 不能单独声明,必须绑定函数式接口

    Lambda是一段匿名代码逻辑,不是变量、不是方法,无法单独存在,必须赋值给函数式接口变量、或直接传入函数式接口参数,否则语法报错。

    7. 禁止在Lambda内修改原集合数据

    遍历集合时,Lambda内部禁止增删、修改原集合元素,会触发并发修改异常(ConcurrentModificationException),也是Stream编程的核心编码规范。

    • 只能作用于函数式接口:多抽象方法接口绝对不能用Lambda

    • 变量隐式final规则:Lambda内部使用的外部局部变量,默认隐式final,不能二次赋值修改

    • 无break/continue:Lambda表达式内部不支持这两个关键字

    • 不能抛出受检异常:如需异常处理,必须手动try-catch

    • 无this、super重写歧义:Lambda没有自己的作用域,this指向外部类对象

    八、Lambda与Stream的关系

    • Stream流的所有中间操作、终端操作(filter、map、forEach等),参数都是内置函数式接口

    • Lambda是Stream的语法基础,没有Lambda,Stream代码会极其繁琐

    • 二者搭配使用,彻底告别for循环遍历、处理集合数据

    赞(0)
    未经允许不得转载:171主机测评 » 超新手的Lambda教程
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址