166. Java Lambda 表达式 – Comparator 高级用法:自定义排序、工厂方法

166. Java Lambda 表达式 – Comparator 高级用法:自定义排序、工厂方法

在某些场景下,我们不希望用“自然顺序”来比较对象(列如按字母顺序、按数字从小到大等),而是想根据某个属性或特征进行比较。

✅ 示例:按字符串长度进行比较(非自然顺序)

Comparator<String> comparator =
    (s1, s2) -> Integer.compare(s1.length(), s2.length());

这是一个简单的比较器,比较的是字符串的“长度”,而不是它们的字典顺序(自然顺序)。换句话说,更短的字符串“更小”


🧠 将比较逻辑提取成Function

我们可以将字符串转换为长度的操作提取出来,使比较器逻辑更加清晰、可重用:

Function<String, Integer> toLength = String::length;

Comparator<String> comparator = (s1, s2) ->
    Integer.compare(toLength.apply(s1), toLength.apply(s2));

这时候,比较器的核心逻辑依赖的是一个函数 toLength,用于将 String 映射为 Integer(长度)。


⚒️ 使用 JDK 提供的工厂方法:Comparator.comparing

更进一步,我们可以用 JDK 中已经内置的 工厂方法 来简化这一过程:

Comparator<String> comparator = Comparator.comparing(String::length);

这行代码的含义是:

根据 String 的长度进行比较,由于 String::length 返回的是 Integer,而 IntegerComparable 类型,所以可以自然排序。


📦 工厂方法 Comparator.comparing 解读

static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> keyExtractor)

  • T: 要比较的对象类型。
  • U: 从对象中提取出来、用于比较的“关键字段”的类型,必须是 Comparable 的子类。
  • keyExtractor: 一个函数,用来提取比较所需的“关键字段”。

🧑💻 实战示例:对 User 列表按名称排序

假设有一个 User 类,并定义了 getName() 方法:

public class User {
    private String name;
    public String getName() { return name; }
    User(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" + "name= " + name +     +  } ;
    }
}

你目前想按名称排序一个 User 列表,可以这样写:

List<User> users = ...;

Comparator<User> byName = Comparator.comparing(User::getName);
users.sort(byName);

也可以一步到位写成:

users.sort(Comparator.comparing(User::getName));


⚠️ 注意事项

  • comparing() 接收的函数,返回值必须是 Comparable 的子类(如 StringInteger 等)。
  • 若你想比较的字段不是 Comparable,可以使用重载版本,手动提供比较器。
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...