Lambda 语法

// 最完整
(int a, int b) -> { return a + b; }

// 类型推断
(a, b) -> { return a + b; }

// 单表达式省 {}
(a, b) -> a + b

// 单参数省 ()
x -> x * 2

// 无参
() -> 42

函数式接口

Lambda 可以赋给任何只有一个抽象方法的接口

@FunctionalInterface
interface Greeter {
    String greet(String name);
}

Greeter g = name -> "Hello, " + name;
g.greet("Alice");    // Hello, Alice

@FunctionalInterface 注解可选——只是让编译器拦截"意外加第二个抽象方法"。

JDK 内置函数式接口

接口 方法签名 用途
Function<T, R> R apply(T) 转换
BiFunction<T, U, R> R apply(T, U) 两参转换
Predicate<T> boolean test(T) 判断
Consumer<T> void accept(T) 消费
Supplier<T> T get() 供给
UnaryOperator<T> T apply(T) T → T
BinaryOperator<T> T apply(T, T) T × T → T
Runnable void run() 无参无返
Callable<V> V call() 无参 + 可抛异常
Function<Integer, Integer> doubled = x -> x * 2;
Predicate<String> nonEmpty = s -> !s.isEmpty();
Consumer<String> print = System.out::println;
Supplier<LocalDate> today = LocalDate::now;
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;

doubled.apply(5);          // 10
nonEmpty.test("hi");        // true
print.accept("hello");
today.get();
add.apply(1, 2);            // 3

方法引用(::)

四种:

ClassName::staticMethod          // String::valueOf
instance::method                  // System.out::println
ClassName::instanceMethod         // String::toUpperCase
ClassName::new                    // ArrayList::new(构造引用)

// 例
Function<Integer, String> f1 = String::valueOf;
Consumer<String> c1 = System.out::println;
Function<String, String> f2 = String::toUpperCase;
Supplier<List<Integer>> s1 = ArrayList::new;

通常比等价 lambda 更短更清楚

list.forEach(s -> System.out.println(s));      // lambda
list.forEach(System.out::println);              // 方法引用,等价但更短

闭包:捕获外部变量

int factor = 10;
Function<Integer, Integer> f = x -> x * factor;

System.out.println(f.apply(5));    // 50

捕获的变量必须 effectively final——不能再被改:

int factor = 10;
Function<Integer, Integer> f = x -> x * factor;
factor = 20;                                     // ❌ 编译错:factor 不是 final

要可变状态用 array hack 或 AtomicInteger:

int[] counter = {0};
list.forEach(s -> counter[0]++);    // 可改数组元素
System.out.println(counter[0]);

但这种用法说明设计有问题——通常应该 stream + reduce 替代。

Lambda 不能抛受检异常

Runnable r = () -> {
    Thread.sleep(1000);    // ❌ throws InterruptedException
};

要么 catch、要么自家包装 + 用自家函数式接口(接受受检异常)。或者用 Lombok @SneakyThrows

Streams 大量用 lambda

List<String> names = users.stream()
    .filter(u -> u.getAge() >= 18)        // Predicate<User>
    .map(User::getName)                    // Function<User, String>
    .sorted(String::compareTo)             // Comparator<String>
    .toList();

详见 第 15 篇

自家函数式接口

@FunctionalInterface
public interface Validator<T> {
    boolean isValid(T value);
}

Validator<String> emailCheck = s -> s.contains("@");
emailCheck.isValid("a@x.com");    // true

复杂签名(多参数 + 受检异常)通常自家声明:

@FunctionalInterface
public interface ThrowingFunction<T, R> {
    R apply(T t) throws Exception;
}

Comparator 组合

List<User> users = ...;

users.sort(Comparator.comparing(User::getAge));
users.sort(Comparator.comparing(User::getAge).reversed());

users.sort(Comparator
    .comparing(User::getDepartment)
    .thenComparing(User::getAge)
    .thenComparing(User::getName));

users.sort(Comparator.comparingInt(User::getAge));   // 避免装箱

链式构造复杂排序——比手写 lambda 清晰。

Predicate 组合

Predicate<User> adult = u -> u.getAge() >= 18;
Predicate<User> active = u -> u.isActive();

Predicate<User> activeAdult = adult.and(active);
Predicate<User> any = adult.or(active);
Predicate<User> minor = adult.negate();

and / or / negate 组合多个条件。

Function 组合

Function<String, String> trim = String::trim;
Function<String, String> lower = String::toLowerCase;

Function<String, String> normalize = trim.andThen(lower);
normalize.apply("  HELLO  ");    // "hello"

// compose:反过来
Function<String, String> rev = lower.compose(trim);
// 等价 trim.andThen(lower)——只是顺序反着写

实战建议

  • 优先 method reference:可读性更好
  • 复杂逻辑 → 抽成命名方法 + 引用:list.stream().filter(this::isValid)
  • lambda 体超过 3 行 → 信号该抽方法
  • 不要让 lambda 有副作用(除了 Consumer 这种本来就该副作用)

→ 下一篇 异常