Skip to content

Lambda 表达式

为什么需要 Lambda?

Lambda 是 Java 8 引入的函数式编程特性,让代码更简洁。

┌─────────────────────────────────────────────────────────────────┐
│                      Lambda 解决的问题                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ❌ 传统写法(匿名内部类)                                          │
│  ─────────────────────                                          │
│  new Thread(new Runnable() {                                    │
│      @Override                                                  │
│      public void run() {                                        │
│          System.out.println("Hello");                            │
│      }                                                          │
│  }).start();                                                    │
│                                                                  │
│  ✅ Lambda 写法                                                  │
│  ─────────────────────                                          │
│  new Thread(() -> System.out.println("Hello")).start();         │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Lambda 语法

基本语法

java
// 完整语法
(参数列表) -> { 方法体 }

// 示例
(int a, int b) -> { return a + b; }

// 简化规则:
// 1. 参数类型可省略
(a, b) -> { return a + b; }

// 2. 单参数括号可省略
name -> System.out.println(name);

// 3. 单行方法体 return 可省略
(a, b) -> a + b

// 4. 单参数类型可省略
String s -> s.length()

示例对比

java
// 完整语法
BiFunction<Integer, Integer, Integer> add = (Integer a, Integer b) -> {
    return a + b;
};

// 省略参数类型
BiFunction<Integer, Integer, Integer> add2 = (a, b) -> {
    return a + b;
};

// 单行省略 return
BiFunction<Integer, Integer, Integer> add3 = (a, b) -> a + b;

// 单参数省略括号
Function<String, Integer> len = s -> s.length();

函数式接口

什么是函数式接口?

只有一个抽象方法的接口,可以用 Lambda 表达式简化。

java
// 函数式接口标记
@FunctionalInterface
public interface MyFunction {
    int apply(int a, int b);
}

// 使用
MyFunction func = (a, b) -> a + b;
System.out.println(func.apply(1, 2));  // 3

常用函数式接口

接口方法说明示例
Supplier<T>T get()生产者() -> "hello"
Consumer<T>void accept(T t)消费者s -> System.out.println(s)
Function<T,R>R apply(T t)转换s -> s.length()
Predicate<T>boolean test(T t)断言s -> s.isEmpty()
UnaryOperator<T>T apply(T t)一元运算x -> x * 2
BinaryOperator<T>T apply(T t1, T t2)二元运算(a, b) -> a + b

常用接口示例

java
// Supplier - 生产数据
Supplier<String> supplier = () -> "Hello";
String result = supplier.get();  // "Hello"

// Consumer - 消费数据
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("Hello");  // 打印 Hello

// Function - 转换数据
Function<String, Integer> function = s -> s.length();
int len = function.apply("Hello");  // 5

// Predicate - 判断
Predicate<String> predicate = s -> s.length() > 3;
boolean test = predicate.test("Hello");  // true

// 组合使用
Function<String, Integer> f = s -> s.length();
Predicate<Integer> p = len -> len > 3;
boolean result = p.test(f.apply("Hello"));  // true

方法引用

四种形式

java
// 1. 静态方法引用  ClassName::staticMethod
Function<Integer, String> toBinary = Integer::toBinaryString;
System.out.println(toBinary.apply(10));  // "1010"

// 2. 实例方法引用  instance::method
String str = "Hello";
Supplier<Integer> len = str::length;
System.out.println(len.get());  // 5

// 3. 任意实例方法引用  ClassName::method
Function<String, Integer> length = String::length;
System.out.println(length.apply("World"));  // 5

// 4. 构造方法引用  ClassName::new
Supplier<Person> personSupplier = Person::new;
Person person = personSupplier.get();

Function<String, Person> personFunction = Person::new;
Person p = personFunction.apply("张三", 25);

方法引用 vs Lambda

java
// Lambda
s -> s.toUpperCase()

// 方法引用(更简洁)
String::toUpperCase

// 比较
list.sort((s1, s2) -> s1.compareTo(s2));
list.sort(String::compareTo);  // 等价

闭包与变量作用域

访问外部变量

java
// Lambda 可以访问外部变量( effectively final)
int base = 10;
Function<Integer, Integer> add = x -> x + base;
System.out.println(add.apply(5));  // 15

// base = 20;  // 编译错误!base 被隐式 final

this 引用

java
public class ThisDemo {

    private String name = "Outer";

    public void test() {
        // Lambda 中的 this 是包围类的 this
        Runnable r = () -> System.out.println(this.name);
        r.run();  // 打印 "Outer"
    }
}

实战应用

集合操作

java
List<String> names = Arrays.asList("Tom", "Jerry", "Mike", "John");

// forEach
names.forEach(name -> System.out.println(name));

// filter + collect
List<String> filtered = names.stream()
    .filter(name -> name.length() > 3)
    .collect(Collectors.toList());

// map 转换
List<Integer> lengths = names.stream()
    .map(name -> name.length())
    .collect(Collectors.toList());

// sort
names.sort((a, b) -> b.compareTo(a));
names.sort(Comparator.reverseOrder());

策略模式

java
// 传统策略模式
interface PaymentStrategy {
    void pay(double amount);
}

class PayByAlipay implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount);
    }
}

// 使用 Lambda(无需创建策略类)
public void pay(double amount, Consumer<Double> paymentMethod) {
    paymentMethod.accept(amount);
}

// 调用
pay(100.0, money -> System.out.println("支付宝支付:" + money));
pay(100.0, money -> System.out.println("微信支付:" + money));

总结

Lambda 核心知识点

知识点说明
语法(params) -> expression(params) -> { statements }
函数式接口只有一个抽象方法的接口
方法引用ClassName::methodinstance::method
变量捕获只能访问 effectively final 变量

⚠️ 易错点提醒

  1. Lambda 表达式外部变量必须是 final 或 effectively final
  2. Lambda 不能访问接口的默认方法
  3. 方法引用 String::length 等价于 s -> s.length()
  4. 构造方法引用 ClassName::new