arrays.binarysearch 并非开箱即快,而是要求数组严格升序、无 null(或 comparator 显式处理)、类型适配(如优先 int[])等前提完备后才释放性能;它不校验有序性,乱序时结果未定义;小数组(jdk8 阈值 21)自动退化为线性扫描;返回值需用 index >= 0 判断命中,否则插入点为 -(index + 1)。

Arrays.binarySearch 不是“一调就快”,而是“准备到位才真快”。它本身不排序、不校验、不兜底,只在你把前提全做对之后,给出一个精准下标或插入位置。性能优势只在条件满足时释放,否则可能比线性扫描还不可靠。
必须先升序排序,且不能靠“看起来有序”
binarySearch 完全不检查数组是否有序,传入乱序数组时,结果未定义——可能返回错误正索引,也可能返回无意义负数,且不会抛异常或警告。常见踩坑场景包括:
- 数据库查出工号列表但没加
ORDER BY emp_id ASC,直接丢给 binarySearch - 前端拼接字符串再 split 成数组(如
"2180,218,217"),未排序就查"218"→ 返回 -1(实际存在) - 浮点数组因
0.1 + 0.2 != 0.3导致微小逆序,排序后仍存在局部错位 - 含 null 的 String[] 或自定义对象数组,但 Comparator 没处理 null,运行时报 NullPointerException
建议上线前加轻量校验:遍历检查 arr[i] ,或用 <code>Stream.iterate 做断言。
小数组走线性扫描,大数组才启用二分
JDK 实现做了实际优化:长度小于阈值(JDK 8 中为 21)时,直接 for 循环遍历,利用 CPU 缓存局部性和分支预测提速;超过阈值才进入标准二分流程。
- 对 10 个元素的数组,binarySearch 实际执行的是线性扫描,不是 mid 计算
- 中点计算用
low + (high - low) / 2或无符号右移(low + high) >>> 1,避免整数溢出 - 循环条件为
low ,确保单元素区间也能被覆盖
返回值不是布尔开关,而是带位置语义的编码
返回值承载双重信息,需按规则解读:
- ≥ 0:找到,数值即为索引(注意:不保证是第一个或最后一个匹配项)
- -(return value + 1),该位置能维持升序
- 例如在
{1, 3, 5, 7}中查4,返回-3→ 插入点 =-(-3 + 1) = 2(插在 3 和 5 之间) - 错误写法:
if (index == -1)—— 这只覆盖“插最前”的情况,漏掉所有其他未命中情形
标准判断仅有一种:if (index >= 0) { /* 找到 */ } else { /* 未找到,插入点 = -(index + 1) */ }
类型与结构选型直接影响性能天花板
不是所有“数组”都适合 binarySearch:
- 优先用
int[]而非Integer[]:避免自动装箱、null 风险和额外对象开销 - 别在
LinkedList上硬套Collections.binarySearch:其get(i)是 O(n),实际比 ArrayList 线性扫描还慢 - 高频查找 + 动态增删?换
TreeSet或TreeMap更合适,它们天然维护有序且支持 O(log n) 查找与更新 - 大数据量下,别每次请求都重建数组:缓存已排序的
int[],只在源头变更时刷新
真正“极速”的关键,是复用升序结构,而非反复 new + sort + search。











