java异常:Comparison method violates its general contract解决

2024-01-07 18:45:22

工作中遇到的一个bug

Comparison method violates its general contract

背景和业务逻辑

这是一个站内通知消息的查询功能
消息分两种 如“原有代码”枚举中的 SINGLE单条/MULTIPLE聚合
规则: 单条读了的消息需要放到聚合消息的后面 单条没读的需要放到聚合消息的前面 聚合消息不用管读没读

线上用户反馈 站内通知消息打不开了

原有代码

public enum NewsDisplayType {
    SINGLE,
    MULTIPLE;
}

private int newsV3Compare(NewsV3 o1, NewsV3 o2) {
	NewsDisplayType displayType1 = o1.getDisplayType();
	NewsDisplayType displayType2 = o2.getDisplayType();
	        
	if (!Objects.equals(displayType1, displayType2)) {
	    if (displayType1.equals(NewsDisplayType.MULTIPLE) && o2.getReadDateTime() != null) {
	        return -1;
	    }
	    return displayType1.compareTo(displayType2);
	}
	.............
}

排查过程

线上通知消息数据粘到测试环境 换成测试用户id 调用接口
控制台打印了Comparison method violates its general contract!
根据栈调用信息定位到了news排序的method

参考了如下文章 了解到 Comparator 要满足自反性,传递性,对称性

https://blog.csdn.net/xdd19910505/article/details/124530002
https://blog.csdn.net/qq_39918677/article/details/120032419

然后 本地 idea 断点 逐行 debug

当执行到 return displayType1.compareTo(displayType2); 的时候 抛出了异常

看代码后发现
这里可能有四种case

case1: o1聚合 o2单条 o2读了 走 return -1 聚合的放前面
case2: o1聚合 o2单条 o2未读 走 return displaytype.compare 聚合的放后面
case3: o1单条 o2聚合 o1未读 走 return displaytype.compare 聚合的放后面
case4: o1单条 o2聚合 o1读了 走 return displaytype.compare 聚合的放后面

因为业务规则里面 是否阅读的规则排序优先于 聚合类型
所以 case4 有问题 违反了反对称性

case1和case4只是交换了o1,o2的顺序 结果出现了不一样的排序结果!!!

修改后的代码

//  两个类型不同 单个未读的<聚合的<单个读了的
    if (!Objects.equals(displayType1, displayType2)) {
        if (displayType1.equals(NewsDisplayType.MULTIPLE)) {
            if (o2.getReadDateTime() != null) {
                // o2/单个 读了 o1/聚和 在前面
                return -1;
            } else {
                // o2/单个 没读 o1/聚和 在后面
                return displayType1.compareTo(displayType2);
            }
        }else{
            if (o1.getReadDateTime() != null) {
                // o1/单个 读了 放后面
                return 1;
            } else {
                // o1/单个 未读 放前面
                return displayType1.compareTo(displayType2);
            }
        }
    }

Ref

https://blog.csdn.net/xdd19910505/article/details/124530002
https://blog.csdn.net/qq_39918677/article/details/120032419

文章来源:https://blog.csdn.net/zhouhangzhouxing/article/details/135409545
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。