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

工作中遇到的一个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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值