Java 8+ 排序API实战:Arrays.sort() 与 Collections.sort() 的3种自定义比较器写法

📅 2026/7/11 8:17:19
Java 8+ 排序API实战:Arrays.sort() 与 Collections.sort() 的3种自定义比较器写法
Java 8 排序API实战Arrays.sort() 与 Collections.sort() 的3种自定义比较器写法在算法竞赛和日常开发中排序是最基础也最频繁使用的操作之一。Java从早期版本就提供了Arrays.sort()和Collections.sort()这两个核心排序方法但直到Java 8引入函数式编程特性后自定义排序规则的写法才真正变得简洁优雅。本文将深入探讨三种现代写法并通过实际案例展示如何应对多级排序等复杂场景。1. 排序基础与核心概念在Java中Arrays.sort()用于数组排序Collections.sort()用于集合排序两者都支持通过自定义比较器Comparator来指定排序规则。理解以下核心概念对掌握排序API至关重要自然排序通过实现Comparable接口的compareTo方法定义对象默认排序规则定制排序通过Comparator实现类定义灵活的、临时的排序规则稳定性相等元素的相对位置在排序后是否保持不变Java的排序算法是稳定的传统写法使用匿名内部类实现Comparator而Java 8之后我们可以用更简洁的Lambda表达式和方法引用来实现相同功能。下面是一个简单对比// 传统写法匿名内部类 Arrays.sort(students, new ComparatorStudent() { Override public int compare(Student s1, Student s2) { return s1.getScore() - s2.getScore(); } }); // Java 8写法Lambda表达式 Arrays.sort(students, (s1, s2) - s1.getScore() - s2.getScore());2. 三种现代比较器写法详解2.1 Lambda表达式写法Lambda表达式是Java 8最显著的特性之一它极大简化了Comparator的实现。基本语法为(参数1, 参数2) - 表达式实际应用示例// 按分数升序排序 Collections.sort(students, (s1, s2) - s1.getScore() - s2.getScore()); // 按姓名字典序排序 Arrays.sort(students, (s1, s2) - s1.getName().compareTo(s2.getName()));提示当比较数值类型时直接相减可能导致整数溢出。更安全的写法是使用Integer.compare(a, b)或Double.compare(a, b)2.2 方法引用写法当排序依据是对象的某个属性时可以使用方法引用进一步简化代码。Comparator.comparing()静态方法是这种写法的核心// 按分数排序 Collections.sort(students, Comparator.comparing(Student::getScore)); // 按姓名排序 Arrays.sort(students, Comparator.comparing(Student::getName));方法引用不仅更简洁而且可读性更强。Comparator.comparing()还支持链式调用方便实现多级排序// 先按班级升序再按分数降序 Arrays.sort(students, Comparator.comparing(Student::getClassId) .thenComparing(Student::getScore, Comparator.reverseOrder()) );2.3 组合比较器写法对于复杂排序需求Java 8提供了组合多个比较器的方法。常用的组合操作包括thenComparing()当前比较结果相等时使用下一个比较器reversed()反转当前比较器的顺序nullsFirst()/nullsLast()处理null值的情况示例代码// 多级排序先按部门再按入职时间最后按工资降序 ListEmployee employees ...; employees.sort( Comparator.comparing(Employee::getDepartment) .thenComparing(Employee::getHireDate) .thenComparing(Employee::getSalary, Comparator.reverseOrder()) ); // 处理可能为null的属性 ListOptionalString names ...; names.sort(Comparator.nullsFirst(Comparator.naturalOrder()));3. 实战多级排序解决方案算法竞赛和实际业务中经常遇到需要多级排序的场景。下面通过两个典型案例展示解决方案。3.1 学生成绩排序案例假设需要先按总分降序排序总分相同则按语文成绩降序最后按学号升序class Student { int id; int chinese; int math; int english; public int getTotal() { return chinese math english; } } ListStudent students ...; students.sort( Comparator.comparingInt(Student::getTotal).reversed() .thenComparingInt(Student::getChinese).reversed() .thenComparingInt(Student::getId) );3.2 电商商品排序案例电商平台常见的多维度排序需求class Product { String category; double price; double rating; LocalDate createTime; } ListProduct products ...; products.sort( Comparator.comparing(Product::getCategory) .thenComparing(Product::getPrice) .thenComparing(Product::getRating, Comparator.reverseOrder()) .thenComparing(Product::getCreateTime, Comparator.reverseOrder()) );4. 性能优化与注意事项虽然现代API写法简洁但在性能敏感场景仍需注意以下要点避免频繁创建比较器对于重复使用的比较器应该缓存实例考虑排序稳定性稳定排序算法在多次排序时能保持之前的相对顺序注意装箱开销对基本类型使用专门的方法如comparingInt()、thenComparingInt()等性能对比示例// 有装箱开销的写法 ComparatorStudent c1 Comparator.comparing(s - s.getScore()); // 无装箱开销的优化写法 ComparatorStudent c2 Comparator.comparingInt(Student::getScore);对于大规模数据排序还可以考虑并行排序// 并行排序数组 Arrays.parallelSort(largeArray); // 并行排序集合 ListStudent largeList ...; largeList.parallelStream() .sorted(Comparator.comparing(Student::getScore)) .collect(Collectors.toList());在实际项目中合理选择排序方法和比较器写法能显著提升代码的可维护性和执行效率。