Equals与CompareTo契约不匹配引发TreeMap键查询异常排查
问题根因定位
你遇到的问题核心是违反了Java Sorted集合(TreeMap、TreeSet等)的强制契约:若a.compareTo(b) == 0,则必须满足a.equals(b) == true,反之亦然。你的Range类中compareTo方法和equals方法的逻辑完全不对齐,直接触发了TreeMap的判断异常。
代码逻辑逐点分析
equals方法实现符合契约:严格要求两个Range的first、last属性完全相等才返回true,逻辑无误。hashCode方法实现符合契约:基于first、last计算哈希值,和equals逻辑完全对齐,无问题。compareTo方法逻辑存在严重错误:
你当前的实现逻辑仅在两个区间完全不重叠时才返回非0值:- 当前区间完全在参数区间左侧(
last < 参数first)返回1 - 当前区间完全在参数区间右侧(
first > 参数last)返回-1 - 其余所有场景(区间重叠、包含、交叉、边界重合)统一返回0
这就导致大量equals返回false的Range对象,compareTo返回0,完全违背了Sorted集合的要求。
- 当前区间完全在参数区间左侧(
故障场景原因说明
TreeMap的所有键判断逻辑(containsKey、get、插入去重等)完全依赖Comparable的compareTo返回值,只要返回0就判定两个键相等,不会再调用equals做校验。因此只要你传入的Range和TreeMap中已存的任意Range存在重叠,就会被判定为键存在,自然就会出现“不存在的键校验也返回存在”的异常表现。
修复方案
如果你的需求是按区间自然排序,需将compareTo逻辑调整为和equals对齐,仅当两个Range的first、last都相等时才返回0:
@Override public int compareTo(Range r) { // 优先比较区间起始值 int firstCompare = this.first.compareTo(r.first); if (firstCompare != 0) { return firstCompare; } // 起始值相等时比较区间结束值 return this.last.compareTo(r.last); }
如果你的业务需要判断区间重叠,需要单独封装isOverlap(Range other)公共方法实现,不能将重叠判断逻辑写在compareTo中。
内容的提问来源于stack exchange,提问作者OPTIMUS
相关产品推荐
相关产品推荐

