减法比较会因整数溢出导致排序逻辑翻转,如integer.max_value - integer.min_value结果为-1;应使用integer.compare(a, b)避免溢出,它通过条件判断返回-1/0/1,性能好且安全。

为什么减法比较在 int 排序中会溢出
直接写 a - b 作为 Comparator 的返回值,看似简洁,但当 a 是极大正数(如 Integer.MAX_VALUE)、b 是极大负数(如 Integer.MIN_VALUE)时,a - b 会整数溢出,结果变成负数,导致排序逻辑完全翻转。这不是边界情况,而是真实可能出现在时间戳、ID、金额等场景中的问题。
例如:Integer.MAX_VALUE - Integer.MIN_VALUE 实际计算为 -1(因为溢出回绕),但语义上它应该是一个很大的正数。
用 Integer.compare() 替代减法的正确写法
Integer.compare(a, b) 内部不依赖算术运算,而是通过条件判断返回 -1、0 或 1,天然规避溢出。它适用于所有需要 int 比较的排序上下文。
- 在
Arrays.sort(int[])中不能直接用——那是原生数组,需用Integer[]+ 自定义Comparator - 对对象字段排序时,比如
list.sort(Comparator.comparingInt(obj -> obj.timestamp)),底层已自动调用Integer.compare(),无需手动干预 - 手写
Comparator时,应写成:(a, b) -> Integer.compare(a.value, b.value),而不是(a, b) -> a.value - b.value
哪些地方容易漏掉、误以为“安全”
开发者常误判某些场景“不会溢出”,结果在线上突然出错。这些是高危点:
- 数据库主键或雪花 ID 转成
int后参与比较(哪怕当前数据小,未来扩容后可能撞上限) - 用
Math.toIntExact(longValue)截断后再减——截断本身可能已出错,且减法仍可能溢出 - 在
TreeSet或TreeMap的自定义Comparator中用减法,会导致树结构损坏,出现查不到、重复插入等诡异行为 - Android 开发中对
View.getId()(返回int)做排序,ID 可能由系统动态分配,范围不可控
性能和兼容性影响几乎为零
Integer.compare() 是 JDK 7 引入的静态方法,编译后基本内联为几条字节码指令,和手写 if 判断性能一致,远优于反射或包装类拆箱开销。
它在 Android API 19+ 完全可用;若需支持更低版本,可复制其源码逻辑(仅 3 行):
public static int compare(int x, int y) {
return (x <p>真正该警惕的不是性能,而是把“看起来能跑通”当成“逻辑正确”——溢出错误往往静默发生,只在特定数据组合下暴露,复现成本高,排查代价大。</p>










