Lambda 与函数式编程
Lambda 表达式
Lambda 是匿名函数的简洁写法,本质是函数式接口的实现。
语法
// 完整写法
(参数列表) -> { 方法体; return 值; }
// 单参数可省略括号
n -> n * 2
// 无参数
() -> System.out.println("hello")
// 多参数
(a, b) -> a + b
// 多行方法体
(a, b) -> {
int sum = a + b;
return sum;
}替代匿名内部类
// 匿名内部类
Comparator<String> cmp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
};
// Lambda
Comparator<String> cmp = (a, b) -> a.compareTo(b);
// 方法引用(更简洁)
Comparator<String> cmp = String::compareTo;方法引用
方法引用是 Lambda 的进一步简化,共四种形式:
| 形式 | 语法 | 等价 Lambda |
|---|---|---|
| 静态方法 | Integer::parseInt | s -> Integer.parseInt(s) |
| 实例方法(任意实例) | String::toUpperCase | s -> s.toUpperCase() |
| 实例方法(特定实例) | obj::method | args -> obj.method(args) |
| 构造器 | User::new | args -> new User(args) |
// 静态方法引用
Stream.of("1","2","3").map(Integer::parseInt);
// 实例方法引用(任意实例)
Stream.of("a","b","c").map(String::toUpperCase);
list.stream().sorted(String::compareTo);
// 实例方法引用(特定实例)
String prefix = "hello";
Stream.of("world").map(prefix::concat); // s -> prefix.concat(s)
PrintStream ps = System.out;
list.forEach(ps::println); // s -> ps.println(s)
// 构造器引用
Stream.of("Alice","Bob").map(User::new); // s -> new User(s)
list.stream().collect(Collectors.toCollection(ArrayList::new));函数式接口
只有一个抽象方法的接口,用 @FunctionalInterface 标注。
JDK 内置接口
// Supplier<T>:无参,有返回值(生产者)
Supplier<List<String>> factory = ArrayList::new;
List<String> list = factory.get();
// Consumer<T>:有参,无返回值(消费者)
Consumer<String> printer = System.out::println;
printer.accept("hello");
// BiConsumer<T,U>:两个参数,无返回值
BiConsumer<String, Integer> print = (s, n) -> System.out.println(s + n);
// Function<T,R>:有参,有返回值(转换)
Function<String, Integer> toInt = Integer::parseInt;
toInt.apply("42"); // 42
// BiFunction<T,U,R>:两个参数,有返回值
BiFunction<String, String, Integer> compare = String::compareTo;
// Predicate<T>:有参,返回 boolean(判断)
Predicate<String> isEmpty = String::isEmpty;
isEmpty.test(""); // true
// UnaryOperator<T>:Function 的特例,输入输出同类型
UnaryOperator<String> trim = String::trim;
// BinaryOperator<T>:BiFunction 的特例,两个同类型参数
BinaryOperator<Integer> add = Integer::sum;
// 数值特化(避免装箱)
IntFunction<String> intToStr = n -> String.valueOf(n);
ToIntFunction<String> strToInt = Integer::parseInt;
IntUnaryOperator square = n -> n * n;
IntBinaryOperator intAdd = Integer::sum;组合
// Function 组合
Function<String, String> trim = String::trim;
Function<String, String> upper = String::toUpperCase;
Function<String, String> trimThenUpper = trim.andThen(upper); // trim 后 upper
Function<String, String> upperAfterTrim = upper.compose(trim); // 先 trim 再 upper
trimThenUpper.apply(" hello "); // "HELLO"
// Predicate 组合
Predicate<Integer> positive = n -> n > 0;
Predicate<Integer> even = n -> n % 2 == 0;
positive.and(even); // n > 0 && n % 2 == 0
positive.or(even); // n > 0 || n % 2 == 0
positive.negate(); // !(n > 0)
// Consumer 组合
Consumer<String> log = s -> System.out.println("LOG: " + s);
Consumer<String> store = s -> db.save(s);
log.andThen(store).accept("data"); // 先 log 再 store闭包与变量捕获
Lambda 可以捕获外部变量,但捕获的变量必须是 effectively final(实际不变):
String prefix = "Hello"; // effectively final
Consumer<String> greeter = name -> System.out.println(prefix + " " + name);
// prefix = "Hi"; // 若取消注释,上面的 Lambda 编译报错
// 实例变量和静态变量可以修改
class Counter {
private int count = 0;
public void increment() {
Runnable r = () -> count++; // 合法,count 是实例变量
r.run();
}
}函数式编程思想
纯函数
相同输入始终产生相同输出,无副作用:
// 纯函数
Function<Integer, Integer> square = n -> n * n;
// 非纯函数(有副作用)
int count = 0;
Function<Integer, Integer> impure = n -> { count++; return n * n; };不可变数据
// 用流替代 for 循环修改状态
List<Integer> nums = List.of(1, 2, 3, 4, 5);
// 命令式(有副作用)
List<Integer> result = new ArrayList<>();
for (int n : nums) {
if (n % 2 == 0) result.add(n * n);
}
// 函数式(无副作用)
List<Integer> result = nums.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.toList();高阶函数
接收或返回函数的函数:
// 返回函数
public static Predicate<Integer> greaterThan(int threshold) {
return n -> n > threshold;
}
Predicate<Integer> gt5 = greaterThan(5);
Predicate<Integer> gt10 = greaterThan(10);
list.stream().filter(gt5).toList();
// 接收函数
public static <T> List<T> filterList(List<T> list, Predicate<T> condition) {
return list.stream().filter(condition).toList();
}
filterList(users, u -> u.getAge() >= 18);
filterList(users, u -> u.getName().startsWith("A"));柯里化
将多参数函数转为单参数函数链:
// 普通双参数
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
// 柯里化
Function<Integer, Function<Integer, Integer>> curriedAdd = a -> b -> a + b;
Function<Integer, Integer> add5 = curriedAdd.apply(5);
add5.apply(3); // 8
add5.apply(10); // 15实战示例
// 策略模式 + Lambda
Map<String, Function<Order, Double>> discountStrategies = Map.of(
"VIP", order -> order.getTotal() * 0.8,
"COUPON", order -> order.getTotal() - 50,
"NORMAL", order -> order.getTotal()
);
double finalPrice = discountStrategies
.getOrDefault(user.getType(), order -> order.getTotal())
.apply(order);
// 责任链 + Lambda
List<UnaryOperator<String>> pipeline = List.of(
String::trim,
String::toLowerCase,
s -> s.replaceAll("\\s+", "-")
);
String result = pipeline.stream()
.reduce(UnaryOperator.identity(), UnaryOperator::andThen)
.apply(" Hello World ");
// "hello-world"