JAVA20-函数式编程与Lambda

函数式编程(Functional Programming,FP)是一种编程范式,它将计算过程视为数学函数的求值,并避免使用程序状态和可变数据。函数式编程的核心思想是使用纯函数(Pure Functions)和不可变数据(Immutable Data)来构建程序。函数式编程可以减少代码量,提高生产力

例如: 有如下类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class User {
    private final Integer id;

    private final String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public static List<User> filter(List<User> users, Predicate<User> predicate) {
        List<User> results = new ArrayList<>();
        for (User user : users) {
            if (predicate.test(user)) {
                results.add(user);
            }
        }
        return results;
    }
}

Lambda表达式

本质是从一种关系到另一种关系的映射

通过Lambda表达式过滤姓王的用户

1
2
3
4
5
// 过滤姓王的用户
public static List<User> filterWangUser(List<User> users) {
    return filter(users, user -> user.getName().startsWith("王"));
    // user -> user.getName().startsWith("王") // 就是lambda表达式
}

方法引用

本质也是从一种关系到另一种关系的映射

通过方法引用过滤姓王的用户

1
2
3
4
5
6
7
8
9
public static boolean isWang(User user) {
    return user.getName().startsWith("王");
}

// 过滤姓王的用户
public static List<User> filterWangUser(List<User> users) {
    return filter(users, User::isWang);
    // User::isWang // 就是方法引用
}

函数接口

你可能会疑惑,为什么方法引用Lambda表达式可以被放到filter方法中的Predicate上?

我们说过了,Lambda表达式和方法引用实际上都是一种关系到另一种关系的映射

我们来看看Predicate接口的定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

Predicate接口定义了一个对象(T)boolean的转换关系,你给我一个对象我把它变成一个boolean值给你,因此所有满足了这个映射关系的方法都可以被传递给Predicate接口,这种接口我们称为函数接口

再来看上面的Lambda表达式和方法引用

  • Lambda
1
2
3
4
5
user -> user.getName().startsWith("王")
// 我们把它拆分为两部分
user // 输入 user 它是一个User类型
-> user.getName().startsWith("王") // 输出,它是一个boolean类型
// 因此这个Lambda表达式满足Predicate接口,因此它可以被传递给Predicate
  • 方法引用
1
2
3
4
public static boolean isWang(User user) {
    return user.getName().startsWith("王");
}
// 这个就更好理解了,输入是User,输出是boolean,因此它也满足Prodicate接口

方法引用相比Lambda表达式的好处是它有名字,更易于理解它在做什么

那么哪些接口可以是函数接口呢?

任何只包含一个抽象方法的接口都可以被自动的转换为函数接口

常见的函数接口

  • java.util.function.*
  • Consumer
  • Predicate
  • Function
  • Supplier

函数接口的一个重要应用接口

  • Comparator
  • comparing

按照什么排序,它应用了Function接口,输入一个类型,按照输出的结果排序

  • reverse 反转
  • thenComparing
updatedupdated2025-03-012025-03-01