运营要求订单列表支持多套动态排序规则,你会怎么设计 Comparator,怎么避免排序结果不稳定?
我的判断
动态排序要把运营输入映射成白名单 Comparator,并始终补一个唯一稳定的兜底键,避免翻页时顺序漂移。
我不会让前端传字段名后直接反射排序。服务端维护可用规则,例如金额、创建时间、优先级,每个规则明确升降序和 null 放前还是放后,再用 thenComparing 组合。最后一定补 orderId,否则两笔金额和时间相同的订单每次顺序可能不同。
Comparator<Order> comparator =
Comparator.comparing(Order::amount, nullsLast(naturalOrder()))
.reversed()
.thenComparing(Order::createdAt)
.thenComparingLong(Order::id);
比较数字不会写 a - b,它可能溢出;字符串是否忽略大小写、金额币种是否一致也要在规则里说清。
如果数据来自数据库,我会把同样的排序规则下推到 SQL,并让游标包含全部排序键。Java 内存排序只适合已经有界的小结果集,不能把几十万订单拉回服务再排。
容易答偏踩坑误区
- Comparator 对同一对元素给出矛盾结果。 TreeSet、排序算法都会出现不可预测行为。
- 没有唯一兜底键。 分页期间相同值记录会重复或遗漏。
- 把用户字段名直接拼进 SQL。 应映射白名单,不能把排序功能变成注入入口。