Lambda 与函数式编程
Java 8 引入的 Lambda 和函数式接口,彻底改变了 Java 的编程风格。理解其底层实现,能帮你写出更简洁高效的代码。
Lambda 底层原理
java
// Lambda 不是匿名内部类!
// 底层使用 invokedynamic 指令 + LambdaMetafactory 实现
// 这段代码:
Runnable r = () -> System.out.println("Hello");
// 编译后大致等价于:
// 1. 生成一个静态方法 lambda$main$0
// 2. 通过 invokedynamic 在运行时动态绑定
// 验证:Lambda 不会生成 $1 这样的内部类文件
// 但匿名内部类会生成 MyClass$1.class函数式接口
java
// Java 8 内置的核心函数式接口
// 都在 java.util.function 包
// Function<T, R> — 接受 T,返回 R
Function<String, Integer> strLen = String::length;
Function<Integer, String> intToStr = Object::toString;
// 组合
Function<String, String> composed = strLen.andThen(intToStr);
// "hello" → 5 → "5"
// Predicate<T> — 接受 T,返回 boolean
Predicate<String> isLong = s -> s.length() > 5;
Predicate<String> startsWithA = s -> s.startsWith("A");
// 组合
Predicate<String> combined = isLong.and(startsWithA);
Predicate<String> either = isLong.or(startsWithA);
Predicate<String> notLong = isLong.negate();
// Consumer<T> — 接受 T,无返回值
Consumer<String> printer = System.out::println;
Consumer<String> logger = s -> log.info(s);
Consumer<String> both = printer.andThen(logger);
// Supplier<T> — 无参数,返回 T
Supplier<List<String>> listFactory = ArrayList::new;
Supplier<LocalDateTime> now = LocalDateTime::now;
// BiFunction<T, U, R> — 接受 T 和 U,返回 R
BiFunction<String, Integer, String> repeat = String::repeat;
// "ha".repeat(3) = "hahaha"
// UnaryOperator<T> — Function<T, T> 的特化
UnaryOperator<String> toUpper = String::toUpperCase;
// BinaryOperator<T> — BiFunction<T, T, T> 的特化
BinaryOperator<Integer> add = Integer::sum;
BinaryOperator<String> concat = String::concat;方法引用
java
// 四种方法引用形式
// 1. 静态方法引用:ClassName::staticMethod
Function<String, Integer> parseInt = Integer::parseInt;
Comparator<String> comp = String::compareTo;
// 2. 实例方法引用(特定实例):instance::method
String prefix = "Hello, ";
Function<String, String> greet = prefix::concat;
// 3. 实例方法引用(任意实例):ClassName::instanceMethod
Function<String, String> toUpper = String::toUpperCase;
Predicate<String> isEmpty = String::isEmpty;
// 4. 构造器引用:ClassName::new
Supplier<ArrayList<String>> listSupplier = ArrayList::new;
Function<Integer, ArrayList<String>> listWithCapacity = ArrayList::new;
BiFunction<String, Integer, StringBuilder> sbFactory = StringBuilder::new;自定义函数式接口
java
// @FunctionalInterface 确保只有一个抽象方法
@FunctionalInterface
public interface Transformer<T, R> {
R transform(T input);
// 可以有默认方法和静态方法
default <V> Transformer<T, V> andThen(Transformer<R, V> after) {
return input -> after.transform(this.transform(input));
}
static <T> Transformer<T, T> identity() {
return t -> t;
}
}
// 使用
Transformer<String, Integer> length = String::length;
Transformer<Integer, String> toStr = n -> "长度: " + n;
Transformer<String, String> combined = length.andThen(toStr);
System.out.println(combined.transform("hello")); // 长度: 5
// 受检异常的函数式接口
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws Exception;
static <T, R> Function<T, R> wrap(CheckedFunction<T, R> fn) {
return t -> {
try {
return fn.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
// 使用
List<String> paths = List.of("file1.txt", "file2.txt");
List<String> contents = paths.stream()
.map(CheckedFunction.wrap(Files::readString)) // 包装受检异常
.collect(Collectors.toList());函数式编程模式
柯里化(Currying)
java
// 将多参数函数转为单参数函数链
Function<Integer, Function<Integer, Integer>> curriedAdd =
a -> b -> a + b;
Function<Integer, Integer> add5 = curriedAdd.apply(5);
System.out.println(add5.apply(3)); // 8
System.out.println(add5.apply(10)); // 15
// 实用场景:部分应用
Function<String, Function<String, String>> format =
template -> value -> template.replace("{}", value);
Function<String, String> greetTemplate = format.apply("Hello, {}!");
System.out.println(greetTemplate.apply("Alice")); // Hello, Alice!
System.out.println(greetTemplate.apply("Bob")); // Hello, Bob!函数组合
java
// 构建处理管道
Function<String, String> trim = String::trim;
Function<String, String> toUpper = String::toUpperCase;
Function<String, String> addPrefix = s -> "PREFIX_" + s;
Function<String, String> pipeline = trim
.andThen(toUpper)
.andThen(addPrefix);
System.out.println(pipeline.apply(" hello "));
// PREFIX_HELLO
// 使用 Stream 构建动态管道
List<Function<String, String>> transforms = List.of(
String::trim,
String::toUpperCase,
s -> s.replace(" ", "_")
);
Function<String, String> combined = transforms.stream()
.reduce(Function.identity(), Function::andThen);
System.out.println(combined.apply(" hello world "));
// HELLO_WORLD现代 Java 特性
java
// Java 16+ Record — 不可变数据类
public record Point(double x, double y) {
// 紧凑构造器(验证)
public Point {
if (x < 0 || y < 0) throw new IllegalArgumentException("坐标不能为负");
}
// 自定义方法
public double distanceTo(Point other) {
return Math.sqrt(Math.pow(x - other.x, 2) + Math.pow(y - other.y, 2));
}
}
Point p = new Point(3, 4);
System.out.println(p.x()); // 3.0(自动生成访问器)
System.out.println(p); // Point[x=3.0, y=4.0]
// Java 17+ Sealed Classes — 限制继承
public sealed interface Shape permits Circle, Rectangle, Triangle {
double area();
}
public record Circle(double radius) implements Shape {
public double area() { return Math.PI * radius * radius; }
}
public record Rectangle(double width, double height) implements Shape {
public double area() { return width * height; }
}
// Java 21 Pattern Matching for switch
double area = switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> t.base() * t.height() / 2;
};函数式编程建议
- 优先使用不可变数据(
record、List.of()、Map.of()) - 用
Optional替代 null 检查 - 用 Stream API 替代命令式循环
- 函数式接口让代码更可测试(传入 mock 函数)