java集合排序核心在于明确“谁比谁大”,分comparable(对象自具备可比性,定义默认顺序)和comparator(外部提供规则,支持灵活多变排序)两类,二者分工协作而非替代。

Java集合排序的核心在于明确“谁比谁大”,实现方式主要分两类:一类是让对象自己具备可比性,另一类是外部提供比较规则。前者用 Comparable,后者用 Comparator。两者不是替代关系,而是分工协作——一个管默认顺序,一个管灵活需求。
让对象自带排序能力:实现 Comparable 接口
当你希望某个类有一个公认的、稳定的排序依据(比如学生按学号排、商品按价格排),就让它实现 Comparable 接口,并重写 compareTo() 方法。这个方法返回负数、0 或正数,分别代表“小于”、“等于”、“大于”。
关键点:
- 必须满足自反性、传递性、反对称性,否则
Collections.sort()或TreeSet可能出错或结果异常 - 只适合一种自然顺序;改规则就得改源码,不够灵活
- 一旦实现,
Arrays.sort()、Collections.sort()、TreeSet、TreeMap都能自动识别并使用
按需定制多种排序:使用 Comparator 接口
当同一类需要不同排序逻辑(如学生既按年龄升序,又按姓名降序),或你无法修改原类(比如对第三方库中的类排序),就该用 Comparator。它不侵入业务类,把比较逻辑抽离出来,运行时传入即可。
常用写法:
- Lambda 表达式:简洁直观,例如
(s1, s2) -> Integer.compare(s1.getAge(), s2.getAge()) - 方法引用:配合
Comparator.comparing()使用,例如Comparator.comparing(Student::getName).reversed() - 链式组合:用
thenComparing()实现多字段排序,例如先按部门,再按薪资:Comparator.comparing(Employee::getDept).thenComparing(Employee::getSalary)
实际场景怎么选
判断依据很简单:
- 如果这个类“天生就该这么排”(比如身份证号唯一且有序),用
Comparable - 如果排序规则会变、有多个、或对象来自外部不可改代码,用
Comparator - 如果只是临时一用(比如调试时按某字段快速查看),Lambda +
sort()最省事
避坑提醒
常见错误容易引发 ClassCastException 或排序失效:
- 在
TreeSet或TreeMap中混存不同类型对象,而它们的compareTo()强制转换类型失败 -
compareTo()或compare()返回值没用Integer.compare()、Double.compare()等安全方法,直接用减法导致整型溢出 - 在
Comparator中比较 null 值未做判空处理,抛NullPointerException











