arrays.binarysearch 并非万能,仅在数组已升序、查找频繁且数据静态时高效;小数组(

Arrays.binarySearch 不是“一搜就快”的魔法方法,它的性能优势只在前提成立时兑现——数组已升序、查找频次高、数据静态或半静态。盲目套用反而可能比线性扫描更慢,尤其对小数组或未排序数据。
小数组走线性扫描,不是 bug 是优化
长度小于 21(JDK 8 默认阈值)的数组,binarySearch 实际执行的是 for 循环遍历,而非中点计算和区间收缩。这不是退化,而是针对现代 CPU 缓存局部性和分支预测做的主动选择。
- 10 个元素的数组查一次,线性扫描通常比三次二分跳转更快
- 该阈值不公开、不可配置,不同 JDK 版本可能微调,无需手动干预
- 若你明确知道数组极小(如配置码表仅 5 项),用
for或Stream.anyMatch语义更清晰,性能差异可忽略
大数组才启用安全二分,但前提是真有序
真正触发经典二分逻辑后,实现细节保障了鲁棒性:
- 中点计算用
low + (high - low) / 2,避免low + high整数溢出 - 循环条件为
low ,确保单元素区间也能被检查 - 未找到时返回
-(insertion point) - 1,插入点定义为第一个大于 key 的索引位置
注意:这个逻辑完全依赖数组升序。传入乱序数组,它仍会跑完全部步骤,但每一步的“砍半”都失去依据,结果纯属巧合。
区间查找不是切片,而是原数组索引映射
四参数版本 binarySearch(arr, from, to, key) 的搜索范围是 [from, to),但返回值始终是原数组的绝对索引,不是子区间的相对偏移。
- 例如在
[10,20,30,40,50]中调用binarySearch(arr, 1, 4, 30),搜索子段[20,30,40],返回2(即原数组索引 2) - 查不到时,插入点也基于区间计算:若 key 小于区间所有元素,返回
-(from + 1);若大于所有,返回-(to + 1) - 不要误以为传了区间就能绕过全局排序——只要
[from, to)这一段本身无序,结果同样不可靠
浮点与对象类型需统一比较契约
对 double[],binarySearch 内部用 Double.doubleToLongBits() 做位级比较,天然支持 NaN 相等、±0.0 区分,但前提是排序也用相同逻辑。
- 用
Arrays.sort(doubleArr)排序,再用binarySearch(doubleArr, key)查找,行为一致 - 若自定义排序(如按绝对值),必须同时用相同 Comparator 调用 binarySearch,否则插入点错乱
- 对象数组含 null 时,未传 Comparator 且元素未实现 Comparable,运行时抛 NullPointerException
不复杂但容易忽略











