Arrays.binarySearch对重复元素只返回任意匹配索引,因算法找到即止、不区分重复值;存在性判断应使用≥0而非≠-1;需边界位置时须手动线性扫描或手写左右边界模板。

Arrays.binarySearch 在遇到重复元素时,只保证返回“某个匹配位置”,不承诺是第一个、最后一个,甚至不保证每次调用结果一致。这不是缺陷,而是设计使然——它面向通用查找场景,而非边界精确定位。
为什么返回位置不确定
二分查找过程本身不区分重复值:只要 mid 位置的元素等于 key,搜索就终止并返回该索引。而 mid 的取值依赖于当前 low/high 区间,不同初始范围或内部计算路径(尤其在子区间查找中)可能导致停在不同重复项上。
- 数组
[10, 10, 20, 20, 20, 30]中查20,可能返回索引 2、3 或 4 - 即使同一数组、同一 key、同一 JVM,多次调用结果也可能不同(取决于内部循环路径,非线程安全问题,而是算法收敛点不唯一)
- 源码中没有“继续向左/右探测”的逻辑,找到即止
如何判断是否存在而非关心具体位置
若业务只需确认元素存在性,直接用返回值是否 ≥ 0 即可,无需额外处理:
-
正确写法:
if (Arrays.binarySearch(arr, key) >= 0) { /* 存在 */ } -
错误写法:
if (Arrays.binarySearch(arr, key) != -1)—— 未找到时返回可能是 -2、-5 等,≠ -1 不等于存在
需要首个或末个位置时怎么办
binarySearch 无法直接满足,必须配合手动扫描或改用自定义边界查找:
- 小范围重复(如最多几十个相同值):先用 binarySearch 定位一个位置,再向左/右线性扩展
- 大数据量或需频繁获取边界:手写 leftBound / rightBound 模板,用 while 循环控制收缩方向
- 示例(找左边界):
int left = pos; while (left > 0 && arr[left - 1] == key) left--;
避免误判的实用建议
重复元素场景下,最容易踩坑的是把返回索引当作“首次出现”来用,或基于它做后续偏移计算:
- 不要假设
binarySearch(arr, key)返回的就是Arrays.stream(arr).filter(x -> x == key).findFirst().orElse(-1)的位置 - 对 String[] 或自定义对象,确保 Comparator 的 equals 和 compare 逻辑一致,否则重复判定可能出错
- 测试时用含重复值的数组覆盖边界:全相同、头尾相同、中间密集重复等

















