Comparator用于定义Java自定义排序逻辑,返回负数/0/正数表示大小关系,需处理空值、多条件组合及中文拼音排序等场景。

用 Comparator 实现自定义排序逻辑
Java 集合本身不带条件排序能力,得靠 Comparator 接口描述“怎么比”。它只关心两个元素谁在前、谁在后,返回负数、0 或正数即可。别写成布尔返回值——那是 Predicate 的事。
常见错误是直接在 sort() 里传一个 lambda 却忽略泛型,比如对 List 写成 (a, b) -> a.length() - b.length() 没问题,但若类型擦除后比较对象字段,编译器可能报错或运行时 ClassCastException。
- 优先用方法引用:比如按字符串长度排,写
Comparator.comparing(String::length)比手写 lambda 更安全 - 多个条件叠加用
thenComparing():如先按年龄升序,年龄相同时按姓名降序,写成comparing(Person::getAge).thenComparing(Person::getName, Comparator.reverseOrder()) - 空值要显式处理:默认
null会抛NullPointerException,用Comparator.nullsFirst()或nullsLast()包一层
Collection.sort() 和 Stream.sorted() 怎么选
核心区别就一条:前者直接改原集合(要求集合可修改),后者返回新流、不碰原数据。如果你排序后还要继续用原列表做其他操作,别用 sort() 把它改乱了。
性能上没本质差异,但 Stream.sorted() 在并行流里能自动分段归并,适合大数据量且已有 parallelStream() 上下文的场景;而 Collection.sort() 底层调的是 Timsort,对小数据更轻量。
立即学习“Java免费学习笔记(深入)”;
- 原地排序且确定集合可变 → 用
Collections.sort(list, comparator) - 不想动原数据,或后续还要 filter/map → 用
list.stream().sorted(comparator).collect(Collectors.toList()) - 排序后只取前 N 条?别先 collect 再 subList,直接
stream().sorted().limit(N).collect()更省内存
实体类字段为空时排序崩溃怎么办
最常见的运行时异常是 java.lang.NullPointerException,发生在比较字段为 null 时调用了 .compareTo() 或 .length() 这类方法。这不是排序逻辑写错了,而是没预设空值策略。
不要手动写 if (a == null && b == null) return 0; else if (a == null) return -1; ... ——太容易漏分支还难维护。Java 8+ 提供了标准解法:
- 字段本身支持自然排序(如
String,Integer):用Comparator.nullsFirst(Comparator.naturalOrder()) - 字段是自定义类型且实现了
Comparable:同上,套一层nullsLast()即可 - 字段是基本类型包装类(如
Integer),但数据库查出来可能是null:避免用a.getValue() - b.getValue(),改用Comparator.nullsLast(Integer::compareTo)
中文字符串按拼音排序不是默认行为
String::compareTo 比的是 Unicode 码点,中文会按 GBK 或 UTF-16 编码顺序排,结果看起来乱序。真要按拼音首字母 A-Z 排,得用 Collator。
注意 Collator.getInstance(Locale.CHINA) 返回的比较器不能直接用于 TreeSet 或 ConcurrentSkipListMap,因为它们要求比较逻辑满足“一致性”,而 Collator 的实现可能不满足严格全序(比如某些生僻字比较结果不稳定)。仅推荐用于一次性排序场景。
- 简单拼音排序:用
Collator.getInstance(Locale.CHINA).compare(a, b)替换 lambda 中的a.compareTo(b) - 想按首字母分组再排序?先用
PinyinUtil.toPinyin(str).charAt(0)(需引入pinyin4j)提取首字母,再按字母排序更可控 - Web 接口返回给前端的列表,如果只是展示用,建议把排序逻辑移到数据库层(
ORDER BY CONVERT(name USING gbk)或 MySQL 8.0+ 的COLLATE utf8mb4_unicode_ci)
实际写条件排序时,最容易被忽略的是空值策略和字符集语义——这两点不出问题时一切正常,一出就是线上 NullPointerException 或用户投诉“名单顺序不对”。










