collections.binarysearch高效需三前提:列表升序、比较逻辑一致、支持随机访问;返回值含位置语义;仅适用arraylist等随机访问list;并发修改或类型不匹配将导致结果错误。

要让 Collections.binarySearch 真正高效,关键不是调用它,而是让它“有据可查”——列表必须已升序排好、比较逻辑前后一致、容器支持随机访问,三者缺一不可。
排序必须提前完成,且只能是升序
binarySearch 从不排序,也不校验顺序。传入乱序、降序或局部错位的列表,结果完全不可信。
- 对
String、Integer等自然有序类型,先调用Collections.sort(list) - 对自定义对象(如
Person),排序和查找必须使用同一个Comparator实例,不能只是“写法相似” - 避免用
stream().sorted()后直接查——那生成的是新列表,原列表仍是乱的 - Lambda 比较器(如
Comparator.comparing(String::toLowerCase))每次调用都新建对象,排序和查找若分别创建,等于用了两个不同比较器
返回值不是布尔值,而是位置信号
它返回的整数自带语义:≥0 表示找到,数值即索引;负数表示未找到,但藏着插入位置。
- 返回
-4→ 插入点是3(计算方式:-(-4) - 1 = 3) - 返回
-1→ 应插在最前面(索引0) - 返回
-6而列表长度为5→ 应插在末尾之后(索引5) - 插入点始终落在
[0, list.size()]范围内,可直接用于list.add(insertionPoint, e)
容器与类型必须严格匹配
看似能跑通,实则暗藏性能或运行时风险。
- 只支持
List,不适用于Set或原始Collection - 推荐用
ArrayList;LinkedList的get(i)是O(n),整个查找退化为线性 - 数组需用
Arrays.asList(arr)包装,但arr必须是包装类型(Integer[]可以,int[]不行) - 列表含
null时,Comparator必须显式处理null,否则抛NullPointerException
并发与泛型边界不可忽视
多线程或类型擦除问题不会立刻报错,但会让结果悄无声息地出错。
- 即使刚排完序,查找过程中若被其他线程修改列表,结果不保证正确
- 推荐将“排序 + 查找”封装为原子操作,或使用不可变列表(如 Guava 的
ImmutableList) - 禁止用原始类型声明列表(如
List list = new ArrayList()),混入不同类型的元素会导致运行时ClassCastException - 自定义类的
compareTo或Comparator必须满足自反性、传递性、一致性,且无副作用











