跳转至

Lambda 与函数式接口

Lambda 就是 Java 版的箭头函数。这是前端人最该觉得亲切的一章——语法几乎一一对应。

Lambda 语法

() -> 表达式               // 无参
x -> x * 2                 // 单参(可省括号)
(x, y) -> x + y            // 多参
(x, y) -> { int z = x+y; return z; }   // 多行用大括号 + return

对标 JS:

() => 表达式
x => x * 2
(x, y) => x + y

函数式接口

Lambda 不是凭空存在的——它必须赋值给一个只有一个抽象方法的接口(函数式接口)。

interface StringProcessor {
    String process(String s);
}
StringProcessor upper = s -> s.toUpperCase();   // lambda 赋值
upper.process("hi");   // HI

JDK 自带的四大函数式接口

不用自己定义,java.util.function 包里有现成的(对标 TS 的函数类型):

接口 签名 对标 TS 用途
Function<T,R> T → R (x: T) => R 转换
Predicate<T> T → boolean (x: T) => boolean 判断/过滤
Consumer<T> T → void (x: T) => void 消费(打印等)
Supplier<T> () → T () => T 生产/提供
Function<String, Integer> length = s -> s.length();
Predicate<String> isLong = s -> s.length() > 3;
Consumer<String> printer = s -> System.out.println(s);
Supplier<String> supplier = () -> "默认值";

方法引用

当 lambda 只是调用某个已有方法时,可以简化成方法引用 类名::方法名

names.forEach(s -> System.out.println(s));   // 完整 lambda
names.forEach(System.out::println);          // 方法引用,等价

对标 JS:把函数当值传递,arr.forEach(console.log)

为什么现在才讲 Lambda

JDK 8 最大的改进就是引入 Lambda。它让集合操作(下一章 Stream)变得极其优雅。Spring 里到处是 Function/Predicate 参数,会读 Lambda 是读懂现代 Java 的前提。

完整可运行示例

package com.javaglm.language.ch15;

import java.util.Arrays;
import java.util.List;
import java.util.function.*;

/**
 * 第 15 章 · Lambda 与函数式接口。
 * Lambda 对标 JS 箭头函数:() -> 表达式。
 * 函数式接口 = 只有一个抽象方法的接口,Lambda 才能赋值给它。
 * JDK 自带一批现成函数式接口(java.util.function),不必自己写。
 */
public class LambdaDemo {

    public static void main(String[] args) {
        List<String> names = Arrays.asList("Tom", "Jerry", "Spike");

        // 1. 基础 lambda:无参
        Runnable r = () -> System.out.println("无参 lambda");
        r.run();

        // 2. 现成函数式接口(对标 TS 的 (s: string) => number 之类的函数类型)
        Function<String, Integer> length = s -> s.length();            // 入→出
        System.out.println("hello 长度 = " + length.apply("hello"));   // 5

        Predicate<String> isLong = s -> s.length() > 3;                // 入→boolean
        System.out.println("Tom 长吗? " + isLong.test("Tom"));         // false

        Consumer<String> printer = s -> System.out.println("打印:" + s);  // 只入无返回
        printer.accept("Hi");

        Supplier<String> supplier = () -> "默认值";                    // 无入有返回
        System.out.println("supply = " + supplier.get());

        // 3. 方法引用:把已有方法当函数传递,更简洁
        names.forEach(System.out::println);   // 等价 s -> System.out.println(s)

        // 4. 多行 lambda 用大括号 + return
        Function<Integer, Integer> square = x -> {
            int result = x * x;
            return result;
        };
        System.out.println("square(5) = " + square.apply(5));
    }
}

:octicons-arrow-left-16: 上一章:泛型 | 下一章:Stream API