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,而Integer是Comparable类型,所以可以自然排序。
📦 工厂方法 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的子类(如String、Integer等)。 - 若你想比较的字段不是
Comparable,可以使用重载版本,手动提供比较器。











网友评论