Comparator接口用于自定义排序规则,解决自然排序单一性问题;通过compare方法定义比较逻辑,结合Lambda、方法引用及Java 8新增的comparing、thenComparing、reversed等链式方法,实现多维度排序;支持null值处理(nullsFirst/nullsLast),并可在Stream API中高效应用,优先使用comparingInt/Long/Double避免装箱开销,适用于复杂或外部类排序场景。

Java中的
Comparator
Comparable
Comparator
解决方案
Comparator
compare(T o1, T o2)
o1
o2
o1
o2
例如,假设我们有一个
Product
name
price
Product
立即学习“Java免费学习笔记(深入)”;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Product {
String name;
double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public double getPrice() { return price; }
@Override
public String toString() {
return "Product{name='" + name + "', price=" + price + '}';
}
}
public class ComparatorDemo {
public static void main(String[] args) {
List<Product> products = new ArrayList<>();
products.add(new Product("Laptop", 1200.0));
products.add(new Product("Mouse", 25.0));
products.add(new Product("Keyboard", 75.0));
products.add(new Product("Monitor", 300.0));
System.out.println("Original: " + products);
// 使用匿名内部类实现按价格排序
Collections.sort(products, new Comparator<Product>() {
@Override
public int compare(Product p1, Product p2) {
return Double.compare(p1.getPrice(), p2.getPrice());
}
});
System.out.println("Sorted by Price (ASC): " + products);
// 使用Lambda表达式实现按名称排序
Collections.sort(products, (p1, p2) -> p1.getName().compareTo(p2.getName()));
System.out.println("Sorted by Name (ASC): " + products);
}
}这里,
Collections.sort()
Comparator
Comparator
Comparator
Java 8对
Comparator
Comparator
核心方法是
Comparator.comparing()
Function
Comparator
thenComparing()
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
String name;
int age;
double salary;
public Employee(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() { return name; }
public int getAge() { return age; }
public double getSalary() { return salary; }
@Override
public String toString() {
return "Employee{name='" + name + "', age=" + age + ", salary=" + salary + '}';
}
}
public class ChainedComparatorDemo {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Alice", 30, 60000.0));
employees.add(new Employee("Bob", 25, 50000.0));
employees.add(new Employee("Charlie", 30, 70000.0));
employees.add(new Employee("David", 25, 55000.0));
employees.add(new Employee("Alice", 35, 65000.0)); // Another Alice
System.out.println("Original: " + employees);
// 链式排序:先按年龄升序,年龄相同再按薪水降序,薪水也相同再按姓名升序
Comparator<Employee> multiFieldComparator = Comparator.comparing(Employee::getAge) // 先按年龄升序
.thenComparing(Comparator.comparing(Employee::getSalary).reversed()) // 年龄相同,按薪水降序
.thenComparing(Employee::getName); // 薪水也相同,按姓名升序
Collections.sort(employees, multiFieldComparator);
System.out.println("Sorted by Age (ASC), then Salary (DESC), then Name (ASC): " + employees);
// 处理null值:假设姓名可能为null
employees.add(new Employee(null, 40, 80000.0));
employees.add(new Employee("Zoe", 40, 80000.0));
// nullsFirst/nullsLast:将null值放在最前面或最后面
Comparator<Employee> nullSafeNameComparator = Comparator.comparing(Employee::getName, Comparator.nullsFirst(String::compareTo));
Collections.sort(employees, nullSafeNameComparator);
System.out.println("Sorted by Name (nulls first): " + employees);
}
}这里我们看到了
Comparator.comparing(Employee::getAge)
thenComparing()
reversed()
Comparator
nullsFirst()
nullsLast()
null
NullPointerException
这真的是一个老生常谈的问题,但每次讨论都觉得很有必要。在我看来,
Comparable
Comparator
Comparable
compareTo(T other)
Student
Comparable
Comparable
Collections.sort(List<T>)
Comparable
而
Comparator
Comparator
所以,我的经验是:
Comparable
Integer
Comparator
Comparator
Comparator
Stream
sorted()
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class StreamComparatorDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Anna");
// 使用Stream API按字母顺序升序排序
List<String> sortedNames = names.stream()
.sorted() // 默认使用String的自然排序
.collect(Collectors.toList());
System.out.println("Sorted names (natural order): " + sortedNames);
// 使用Stream API按字符串长度降序排序
List<String> sortedByLengthDesc = names.stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.collect(Collectors.toList());
System.out.println("Sorted by length (DESC): " + sortedByLengthDesc);
// 复杂对象在Stream中的排序:先按年龄升序,再按姓名降序
List<Employee> employees = Arrays.asList(
new Employee("Alice", 30, 60000.0),
new Employee("Bob", 25, 50000.0),
new Employee("Charlie", 30, 70000.0),
new Employee("David", 25, 55000.0),
new Employee("Anna", 30, 60000.0)
);
List<Employee> sortedEmployees = employees.stream()
.sorted(Comparator.comparing(Employee::getAge)
.thenComparing(Employee::getName, Comparator.reverseOrder())) // 姓名降序
.collect(Collectors.toList());
System.out.println("Sorted Employees (Age ASC, Name DESC): " + sortedEmployees);
// 性能考量:使用comparingInt/Long/Double
// 当排序的键是基本类型(int, long, double)时,优先使用comparingInt(), comparingLong(), comparingDouble()。
// 它们避免了自动装箱/拆箱的性能开销,比单纯的comparing()更高效。
// 例如:Comparator.comparingInt(Employee::getAge) 比 Comparator.comparing(Employee::getAge) 更好。
// 虽然对于小规模数据可能感知不强,但在处理大数据量时,这种优化是值得的。
// 我在一些性能敏感的后端服务中,会特别注意这些细节,积少成多嘛。
}
}在
Stream
sorted()
Comparable
Comparator
Comparator.comparing()
thenComparing()
reversed()
关于性能,我不得不提一下
comparingInt()
comparingLong()
comparingDouble()
int
long
double
Comparator.comparing()
Integer
long
double
Comparator
以上就是Java中Comparator接口使用技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号