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这种本来就该副作用)
→ 下一篇 异常