直接用Collections.sort()对自定义对象列表排序会报ClassCastException,因未提供比较依据;需实现Comparable或传入Comparator,推荐JDK8+的Comparator.comparing()链式写法。

直接用 Collections.sort() 对自定义对象列表排序,大概率会报错——因为 Java 不知道你希望按什么字段、什么顺序排。关键不是“能不能排”,而是“怎么告诉它怎么排”。
先搞清报错原因:不是语法错,是逻辑缺位
常见错误如 ClassCastException: Person cannot be cast to Comparable,本质是:你没提供任何比较依据。Java 要求要么对象自己声明“我会比大小”(实现 Comparable),要么你现场给一套规则(传入 Comparator)。两者缺一不可。
- 如果类有唯一公认的排序方式(比如学生永远按学号升序),就让类实现
Comparable<Student>,重写compareTo() - 如果同一类需要多种排序(比如有时按年龄升序,有时按姓名降序),就别改类,用
Comparator临时指定规则 - 千万别在
compareTo()里用==比字符串,或直接用a - b算整数差——溢出或空指针风险高
用 Comparator.comparing() 链式构造,清晰又安全
JDK 8+ 推荐写法,可读性强、支持 null 处理和多级排序。核心是用方法引用代替冗长 lambda,再用 .thenComparing() 追加次级条件。
- 单字段升序:
Comparator.comparing(Person::getAge) - 单字段降序:
Comparator.comparing(Person::getAge).reversed() - 多级排序(先按年龄升序,年龄相同时按姓名降序):
Comparator.comparing(Person::getAge).thenComparing(Person::getName, String.CASE_INSENSITIVE_ORDER.reversed()) - 字段可能为 null?加上
nullsLast():Comparator.nullsLast(Comparator.comparing(Person::getPhone))
手写 Comparator Lambda:简单场景够用,但要注意细节
适合快速验证或逻辑极简的场景,但必须手动处理边界情况。
- 避免
a.getAge() - b.getAge():int 溢出时结果反转(如 2000000000 - (-2000000000) 得负数)→ 改用Integer.compare(a.getAge(), b.getAge()) - 字符串比较别用
a.getName().compareTo(b.getName())直接调用,除非确认非空;否则先判空或用String.CASE_INSENSITIVE_ORDER.compare(a.getName(), b.getName()) - 多条件嵌套判断易出错,不如链式
comparing().thenComparing()直观
别踩这些运行时坑
代码编译通过 ≠ 运行正常。几个高频陷阱:
- 传入的 List 是
Collections.unmodifiableList()或Arrays.asList()返回的只读视图 → 报UnsupportedOperationException - 排序过程中其他线程在修改该 List → 结果不可预测,
Collections.sort()本身不加锁 - 用了
Comparator.comparing()但字段 getter 返回 null → 触发NullPointerException,务必搭配nullsFirst()/nullsLast() - 误以为
Collections.sort()返回新列表 → 它是原地修改,返回 void,原 List 顺序已变


















