comparator.compare()返回值不必是-1/0/1,只需负数表示小于、0表示相等、正数表示大于;推荐用integer.compare()等工具方法避免溢出,链式排序用thencomparing()并处理null,arrays.sort()与collections.sort()不可混用,lambda中捕获的局部变量须为effectively final。

Comparator.compare() 返回值为什么必须是 -1/0/1?
不是必须返回 -1/0/1,只要符合「负数表示小于、0表示相等、正数表示大于」的语义即可。JDK 内部只做符号判断,compare() 返回 -100 或 5 都合法。但写成 -1/0/1 容易掩盖逻辑错误——比如用减法比较 int 时溢出:a - b 可能从正变负,导致排序错乱。
推荐写法:
- 对基本类型用
Integer.compare(a, b)、Double.compare(a, b) - 对字符串用
String.compareTo(),别自己写s1.length() - s2.length() - 自定义对象字段比较,优先组合
Comparator.comparing(),避免手写compare()
如何链式组合多个排序条件?
用 thenComparing() 最安全。比如先按年龄升序,年龄相同时按姓名降序:
Comparator<Person> cmp = Comparator.comparing(p -> p.age)
.thenComparing(p -> p.name, Comparator.reverseOrder());注意点:
立即学习“Java免费学习笔记(深入)”;
-
thenComparing()的第二个参数是另一个Comparator,不是布尔值 - 如果字段可能为
null,必须显式处理:用Comparator.nullsFirst()或Comparator.nullsLast() - 不要嵌套写
thenComparing().thenComparing().thenComparing()超过 3 层,可读性骤降,建议提取为常量
Arrays.sort() 和 Collections.sort() 能混用吗?
不能直接混用。前者只接受 T[] + Comparator super T>,后者只接受 List<t></t> + Comparator super T>。传错类型会编译失败,比如把 ArrayList 传给 Arrays.sort() 会报 no suitable method found。
常见误操作:
- 对
int[]用Arrays.sort(arr, cmp)→ 编译错误,int[]不支持泛型Comparator,得先转成Integer[] - 对不可变
List(如Arrays.asList()返回的)调用Collections.sort()→ 运行时抛UnsupportedOperationException - 在多线程环境下对同一集合反复调用
sort()且未同步 → 结果不可预测,sort()不是线程安全的
Lambda 写 Comparator 时捕获局部变量要注意什么?
Lambda 中引用的局部变量必须是「事实上 final」(effectively final),即声明后未再赋值。否则编译报错:local variables referenced from a lambda expression must be final or effectively final。
典型场景是动态指定排序字段名(如用户选择“按价格”或“按销量”):
String sortBy = "price";
List<Product> list = ...;
list.sort((a, b) -> {
if ("price".equals(sortBy)) return Double.compare(a.price, b.price);
else return Integer.compare(a.sales, b.sales);
});这里 sortBy 没被重新赋值,所以合法。但如果在 Lambda 外又写了 sortBy = "sales",就会编译失败。
更健壮的做法是把逻辑提前封装,避免在 Lambda 里做分支判断:
Comparator<Product> cmp = "price".equals(sortBy)
? Comparator.comparing(p -> p.price)
: Comparator.comparing(p -> p.sales);排序逻辑本身不难,难的是 null 值、类型擦除、线程干扰这些边界情况——它们往往在测试环境不暴露,上线后才突然崩。








