【java进阶】------ Lambda表达式

关于匿名内部类的详细知识点,请查阅《【java面向对象进阶】------内部类》

关于Array的排序规则请参考本文《【java常用API】----- Arrays》


1. 什么是函数式编程

在正式学习Lambda之前,我们需要先理解一种编程思想:函数式编程(Functional Programming)

  • 面向对象思想:强调"谁去做"。做事情必须先找一个对象,通过对象调用方法来完成。
  • 函数式思想:强调"做什么"。它忽略面向对象的复杂语法,只关注结果,不关注执行的对象是谁。

Lambda表达式正是函数式思想在Java中的具体体现。


2. Lambda表达式的标准格式

Lambda表达式是JDK 8引入的一种新语法形式,它的核心作用是简化匿名内部类的写法

2.1 标准语法结构

Lambda表达式的标准格式由三个部分组成:

java 复制代码
(参数列表) -> { 方法体代码 }
  • ():对应着接口中抽象方法的形参列表
  • ->:Lambda操作符(箭头操作符),是固定格式,表示指向。
  • {}:对应着接口中抽象方法的方法体

2.2 代码演变:从匿名内部类到Lambda

让我们通过Arrays.sort的降序排序案例,看看代码是如何演变的。

需求:对整数数组进行降序排序。

2.2.1 传统写法:匿名内部类

java 复制代码
Integer[] arr = {3, 1, 4, 2};

Arrays.sort(arr, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1;
    }
});

2.2.2 Lambda写法:简化后的代码

java 复制代码
Integer[] arr = {3, 1, 4, 2};

// Lambda完整格式
Arrays.sort(arr, (Integer o1, Integer o2) -> {
    return o2 - o1;
});

对比分析

  • 我们省略了new Comparator<>() { ... }这一大串模板代码。
  • 我们只保留了最核心的参数(o1, o2)和执行逻辑-> { return o2 - o1; }

3. Lambda表达式的前提条件

并不是所有的匿名内部类都能用Lambda表达式简化,必须满足以下前提:

  1. 必须是接口的匿名内部类
  2. 接口中只能有一个抽象方法

满足上述条件的接口,被称为函数式接口

💡 知识点:@FunctionalInterface

这是一个注解,用于检测一个接口是否是函数式接口。如果接口上有此注解,但包含多个抽象方法,编译器会报错。虽然不写这个注解也能运行,但为了代码的严谨性,建议在函数式接口上加上此注解。


4. Lambda表达式的省略写法

Lambda之所以流行,是因为它支持大量的语法省略。其核心原则只有一条:可推导,可省略。即编译器能根据上下文推导出类型的,都可以省略。

4.1 省略规则速查表

规则描述 示例(假设接口方法为 void run()int compare(...)
参数类型可省略 (Integer o1, Integer o2)(o1, o2)编译器根据泛型自动推断类型
单参数可省略括号 仅有一个参数省略了类型 ,则 () 可省略。例如:(e)e(若保留类型如 (String e),则括号不可省)
单行代码可省略大括号 若方法体仅有一行代码,{};return同时省略 。例如:(x, y) -> { return x + y; }(x, y) -> x + y

4.2 省略演示

让我们继续使用排序的例子,看看代码是如何一步步"瘦身"的。

场景 :对整数数组进行降序排序。

4.2.1 第一阶段:Lambda完整格式

java 复制代码
Arrays.sort(arr, (Integer o1, Integer o2) -> {
    return o2 - o1;
});

4.2.2 第二阶段:省略参数类型

编译器可以通过arr数组的类型推导出o1o2都是Integer类型。

java 复制代码
Arrays.sort(arr, (o1, o2) -> {
    return o2 - o1;
});

4.2.3 第三阶段:省略大括号、return和分号

因为方法体只有一行代码,我们可以将其简化为一行流式写法。

java 复制代码
// 最终形态
Arrays.sort(arr, (o1, o2) -> o2 - o1);

5. 实战练习:字符串长度排序

为了巩固Lambda的使用,我们来完成一个实际的小练习。

需求

  1. 定义一个字符串数组 {"a", "aaaa", "aaa", "aa"}
  2. 使用Arrays.sort进行排序。
  3. 排序规则 :按照字符串的长度进行降序排序(长的在前,短的在后)。

5.1 传统匿名内部类写法

java 复制代码
package com.example;
import java.util.Arrays;
import java.util.Comparator;

public class ArraysDemo {
    public static void main(String[] args) {
        String[] arr = {"a", "aaaa", "aaa", "aa"};

        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 按照长度比较:o2长度 - o1长度
                return o2.length() - o1.length();
            }
        });
        //输出结果:[aaaa, aaa, aa, a]
        System.out.println(Arrays.toString(arr));
    }
}

5.2 Lambda省略写法(推荐)

我们可以直接利用省略规则,将代码简化到最极致:

java 复制代码
package com.example;
import java.util.Arrays;

public class ArraysDemo {
    public static void main(String[] args) {
        String[] arr = {"a", "aaaa", "aaa", "aa"};
        // 参数类型省略 + 大括号/return省略
        Arrays.sort(arr,(o1,o2) -> o2.length()-o1.length());
        //输出结果:[aaaa, aaa, aa, a]
        System.out.println(Arrays.toString(arr));
    }
}

5.3 扩展知识:空指针风险与防御式编程

在实际开发中,如果数组中混入了 null 值,直接调用 .length() 会立即抛出 NullPointerException

Java 8 的 Comparator 提供了 nullsFirstnullsLast 工厂方法,能让我们优雅地定义空值的排序位置(排最前或排最后),从而避免程序崩溃。

示例:将 null 值视为最小值,排在最前面

java 复制代码
// 处理可能包含 null 的字符串数组
Arrays.sort(arr, Comparator.nullsFirst(Comparator.comparing(String::length)));
相关推荐
plainGeekDev2 分钟前
RecyclerView.Adapter → ListAdapter
java·kotlin·gradle
J2虾虾13 分钟前
Spring AI Alibaba - 人工介入(Human-in-the-Loop)
java·人工智能·spring
Old Uncle Tom34 分钟前
Harness Engineering 综述
java·开发语言·数据库
星原望野37 分钟前
JAVA:策略模式的实战使用
java·开发语言·策略模式
码界筑梦坊37 分钟前
282-基于Python的豆瓣音乐可视化分析推荐系统
开发语言·python·信息可视化·数据分析·flask·vue
LJianK138 分钟前
java多态
java·开发语言·python
_Evan_Yao39 分钟前
栈与队列:后进先出与先进先出的智慧
开发语言·python
z落落1 小时前
C# 构造函数(无参/有参/重载/this)+析构函数(终结器)|GC 垃圾回收
java·开发语言·c#
武子康1 小时前
Java-12 深入浅出 MyBatis 二级缓存详解:跨 SqlSession 共享与失效机制
java·后端
考虑考虑1 小时前
JDK9中的Set.of()使用注意
java·后端·java ee