必须预排序。collections.binarysearch要求list已严格升序且比较逻辑一致,否则结果不可预测;排序仅需一次,后续插入用binarysearch定位再add维持有序;须统一使用自然序或同一comparator;仅randomaccess列表(如arraylist)可保障o(log n)性能;返回值为索引(≥0)或插入点(负值)。

对,必须预排序。Collections.binarySearch 不做任何排序动作,它只假设你传进去的 List 已经严格有序——升序,且排序依据与查找时使用的比较逻辑完全一致。跳过这步,结果就不可预测:可能返回负数说“没找到”,其实元素就在里面;也可能返回一个正数索引,但指向的是错误元素。
排序必须一次性完成,不能每次查都重排
排序是 O(n log n) 开销,而 binarySearch 是 O(log n)。如果在循环里反复调用 Collections.sort() 再查,性能反而比线性遍历还差。正确做法是:
- 初始化阶段排序一次,之后只读查找
- 有新元素插入时,用 binarySearch 找到插入位置,再用 list.add(index, item) 维持有序,避免全量重排
- 数据来自数据库或外部接口时,优先让源头按主键升序返回,省去客户端排序压力
排序和查找必须用同一套比较规则
自然序(元素实现 Comparable)和自定义 Comparator 不能混用。常见错误是:用 Comparator 排了序,调用 binarySearch 时却没传这个 Comparator,结果查不到。
- 若用 Collections.sort(list, comp),后续 binarySearch 必须写成 Collections.binarySearch(list, key, comp)
- 不推荐依赖自然序 + 自定义对象,除非该类明确、稳定地实现了 compareTo
- Comparator 内部别做耗时操作(如解析字符串、调用 getter 反射),应轻量直接比字段值
List 类型要支持随机访问
binarySearch 在内部频繁调用 get(i),所以只有实现 RandomAccess 接口的 List(比如 ArrayList、Arrays.asList 返回的列表)才能真正达到 O(log n)。LinkedList 虽然能调用,但每次 get(i) 是 O(n),整体退化为 O(n) 查找。
- 用 list instanceof RandomAccess 做运行时校验,避免误用
- 高频查找场景下,别为了“链表语义”选 LinkedList,ArrayList 更合适
- 如果数据结构天然动态增删多、查找少,考虑改用 TreeSet 或 ConcurrentHashMap + 排序视图
返回值不是布尔,要按规则解码
返回值是整数,含义需主动判断:
- ≥ 0:表示找到,值就是元素在 List 中的索引
- 别直接用返回值做 list.get(),先判断符号,否则容易抛 IndexOutOfBoundsException











