【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)));
相关推荐
码云数智-大飞2 小时前
Java接口与抽象类:从本质区别到架构选型
开发语言
小碗羊肉2 小时前
【从零开始学Java | 第二十三篇】泛型(Generics)
java·开发语言·新手入门
m0_750580302 小时前
Java并发—Java线程
java·开发语言
我不是懒洋洋2 小时前
预处理详解
c语言·开发语言·c++·windows·microsoft·青少年编程·visual studio
QuZero2 小时前
JDK7 ConcurrentHashMap principle
java·哈希算法
计算机安禾2 小时前
【数据结构与算法】第14篇:队列(一):循环队列(顺序存储
c语言·开发语言·数据结构·c++·算法·visual studio
独断万古他化3 小时前
【Java 实战项目】多用户网页版聊天室:消息传输模块 —— 基于 WebSocket 实现实时通信
java·spring boot·后端·websocket·ajax·mybatis
yyt3630458413 小时前
spring单例bean线程安全问题讨论
java·spring
weixin_649555673 小时前
C语言程序设计第四版(何钦铭、颜晖)第十一章指针进阶之奇数值结点链表
c语言·开发语言·链表