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::parseInts -> Integer.parseInt(s)
实例方法(任意实例)String::toUpperCases -> s.toUpperCase()
实例方法(特定实例)obj::methodargs -> obj.method(args)
构造器User::newargs -> 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"

相关链接