Java 完全指南 / 16 - Lambda:函数式接口、方法引用、Comparator
16 - Lambda:函数式接口、方法引用、Comparator
Lambda 表达式
public class LambdaDemo {
public static void main(String[] args) {
// 传统匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda 写法
Runnable r2 = () -> System.out.println("Hello");
// Lambda 多行
Runnable r3 = () -> {
String name = "Java";
System.out.println("Hello, " + name);
};
// 带参数
java.util.function.Consumer<String> printer = s -> System.out.println(s);
java.util.function.Function<String, Integer> len = s -> s.length();
java.util.function.Predicate<String> notEmpty = s -> !s.isEmpty();
java.util.function.Supplier<List<String>> listFactory = ArrayList::new;
// 使用
printer.accept("Hello");
System.out.println(len.apply("Java"));
System.out.println(notEmpty.test(""));
}
}
函数式接口(@FunctionalInterface)
@FunctionalInterface
interface MathOperation {
int operate(int a, int b);
// 可以有默认方法
default MathOperation andThen(MathOperation after) {
return (a, b) -> after.operate(operate(a, b), b);
}
}
// 使用
public class FunctionalInterfaceDemo {
public static void main(String[] args) {
MathOperation add = Integer::sum;
MathOperation multiply = (a, b) -> a * b;
System.out.println(add.operate(3, 5)); // 8
System.out.println(multiply.operate(3, 5)); // 15
}
}
java.util.function 核心接口
| 接口 | 签名 | 示例 |
|---|---|---|
Function<T,R> | R apply(T t) | String::length |
Predicate<T> | boolean test(T t) | s -> s.isEmpty() |
Consumer<T> | void accept(T t) | System.out::println |
Supplier<T> | T get() | ArrayList::new |
UnaryOperator<T> | T apply(T t) | String::toUpperCase |
BinaryOperator<T> | T apply(T a, T b) | Integer::sum |
BiFunction<T,U,R> | R apply(T t, U u) | (a,b) -> a+b |
BiPredicate<T,U> | boolean test(T t, U u) | Objects::equals |
BiConsumer<T,U> | void accept(T t, U u) | Map::put |
import java.util.function.*;
public class FunctionDemo {
public static void main(String[] args) {
// Function 组合
Function<String, String> trim = String::trim;
Function<String, String> upper = String::toUpperCase;
Function<String, String> process = trim.andThen(upper);
System.out.println(process.apply(" hello ")); // HELLO
Function<Integer, Integer> doubleIt = n -> n * 2;
Function<Integer, Integer> addOne = n -> n + 1;
Function<Integer, Integer> doubleThenAdd = doubleIt.andThen(addOne);
Function<Integer, Integer> addThenDouble = doubleIt.compose(addOne);
System.out.println(doubleThenAdd.apply(5)); // 11 (5*2+1)
System.out.println(addThenDouble.apply(5)); // 12 ((5+1)*2)
// Predicate 组合
Predicate<String> isLong = s -> s.length() > 5;
Predicate<String> startsWithH = s -> s.startsWith("H");
Predicate<String> combined = isLong.and(startsWithH);
Predicate<String> negated = isLong.negate();
System.out.println(combined.test("Hello World")); // true
System.out.println(combined.test("Hi")); // false
// BiFunction
BiFunction<String, Integer, String> repeat = (s, n) -> s.repeat(n);
System.out.println(repeat.apply("Ha", 3)); // HaHaHa
}
}
方法引用
public class MethodRefDemo {
static void print(String s) { System.out.println(s); }
public static void main(String[] args) {
List<String> names = List.of("Charlie", "Alice", "Bob");
// 1. 静态方法引用: ClassName::staticMethod
names.forEach(MethodRefDemo::print);
// 2. 实例方法引用: instance::method
String prefix = "Hello, ";
Function<String, String> greeter = prefix::concat;
// 3. 任意对象方法引用: ClassName::instanceMethod
names.stream()
.map(String::toLowerCase)
.forEach(System.out::println);
// 4. 构造器引用: ClassName::new
Function<String, StringBuilder> sbFactory = StringBuilder::new;
Supplier<ArrayList<String>> listFactory = ArrayList::new;
BiFunction<String, Integer, record_> recFactory = SomeRecord::new;
// 数组构造器引用
IntFunction<String[]> arrayFactory = String[]::new;
String[] arr = arrayFactory.apply(5); // new String[5]
}
record SomeRecord(String name, int age) {}
}
Comparator 详解
import java.util.*;
public class ComparatorDemo {
record Student(String name, int age, double score) {}
public static void main(String[] args) {
List<Student> students = new ArrayList<>(List.of(
new Student("张三", 20, 92.5),
new Student("李四", 22, 85.0),
new Student("王五", 21, 92.5),
new Student("赵六", 20, 78.0)
));
// 自然排序
List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
names.sort(Comparator.naturalOrder());
names.sort(Comparator.reverseOrder());
// Comparator.comparing
students.sort(Comparator.comparing(Student::name));
students.sort(Comparator.comparingDouble(Student::score).reversed());
// 多条件排序
students.sort(
Comparator.comparingDouble(Student::score).reversed() // 分数降序
.thenComparing(Student::name) // 姓名升序
);
// nullsFirst / nullsLast
students.sort(Comparator.comparing(Student::name, Comparator.nullsLast(String::compareTo)));
// 自定义 Comparator
Comparator<Student> byAge = (a, b) -> Integer.compare(a.age(), b.age());
students.sort(byAge);
students.forEach(s -> System.out.printf("%s: %.1f%n", s.name(), s.score()));
}
}
实用 Lambda 模式
public class LambdaPatterns {
// 条件过滤器构建器
static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
// 缓存/记忆化
static <T, R> Function<T, R> memoize(Function<T, R> fn) {
Map<T, R> cache = new HashMap<>();
return t -> cache.computeIfAbsent(t, fn);
}
// 重试机制
static <T> T retry(int maxAttempts, Supplier<T> action) {
Exception lastException = null;
for (int i = 0; i < maxAttempts; i++) {
try {
return action.get();
} catch (Exception e) {
lastException = e;
}
}
throw new RuntimeException("重试" + maxAttempts + "次后失败", lastException);
}
public static void main(String[] args) {
// 条件过滤
List<String> items = List.of("A", "", "B", " ", "C");
List<String> nonEmpty = items.stream().filter(not(String::isBlank)).toList();
// 记忆化斐波那契
Function<Integer, Long> fib = memoize(n -> {
if (n <= 1) return (long) n;
return fib.apply(n - 1) + fib.apply(n - 2);
});
System.out.println(fib.apply(50)); // 快速计算
// 重试
String result = retry(3, () -> {
if (Math.random() < 0.7) throw new RuntimeException("失败");
return "成功";
});
}
}
⚠️ 注意事项
- Lambda 中只能访问 effectively final 变量 — 不能修改外部局部变量。
- 不要过度使用 Lambda — 复杂逻辑仍应使用方法引用或普通方法。
- Lambda 没有 checked exception — 需要包装为 unchecked 或使用辅助方法。
- Lambda 序列化问题 — Lambda 不能直接序列化,需要特殊处理。
💡 技巧
处理 checked exception 的 Lambda:
@FunctionalInterface interface ThrowingFunction<T, R> { R apply(T t) throws Exception; } static <T, R> Function<T, R> unchecked(ThrowingFunction<T, R> fn) { return t -> { try { return fn.apply(t); } catch (Exception e) { throw new RuntimeException(e); } }; } // 使用: list.stream().map(unchecked(File::getCanonicalPath))链式条件构建:
Predicate<User> isVip = User::isVip; Predicate<User> isAdult = u -> u.getAge() >= 18; Predicate<User> canAccess = isVip.and(isAdult);
🏢 业务场景
- 策略模式: 使用 Lambda 替代策略接口实现。
- 事件处理: Swing/JavaFX 事件回调。
- 数据处理: Stream + Lambda 进行集合过滤、转换。
- 异步编程: CompletableFuture 的回调函数。