java 【排序】异常:java.lang.IllegalArgumentException: Comparison method violates its general contract!

环境

java:1.7

前言

本来是不想写这篇的,但是最近老报这个错误,一开始,我以为解决了,后来发现不是那么回事

现在特意记录下

我的排序代码

我先贴出完整的排序代码:

/**
 * 支持两个字段排序
 * @param result
 * @param order
 * @param orderType
 * @param twoOrder 第二排序字段
 * @param twoType 第二排序顺序
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:00:03
 */
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType, 
                                                    final String twoOrder, final Integer twoType){

    if(result == null || orderType == null){
        return result;
    }

    if(orderType != -1){
        orderType = 1;
    }

    final String orderKey = order;
    final Integer oType = orderType;

    Collections.sort(result, new Comparator<Map<String, Object>>() {
        @Override
        public int compare(Map<String, Object> o1, Map<String, Object> o2) {
            Object obj1 = o1.get(orderKey);
            Object obj2 = o2.get(orderKey);
            return commonOrder(orderKey, oType, obj1, obj2, twoOrder, twoType);
        }
    });
    return result;
}

/**
 * 公共的排序部分
 * @param orderKey
 * @param oType
 * @param obj1
 * @param obj2
 * @param twoOrder
 * @param twoType
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:19:37
 */
public static Integer commonOrder(final String orderKey, final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    //重点注意
    if(obj1 == null && obj2 == null){
        return 0;
    }
    if (obj1 == null) {
        if(oType < 0){
            return -oType;
        }
        return oType;
    }
    if (obj2 == null) {
        if(oType < 0){
            return oType;
        }
        return -oType;
    }

    if(obj1 instanceof Date && obj2 instanceof Date){
        //日期排序
        Date date1 = (Date)obj1;
        Date date2 = (Date)obj2;
        return longCompare(oType, date1.getTime(), date2.getTime(), twoOrder, twoType);
    }else if(obj1 instanceof String && obj2 instanceof String){
        //字符串排序
        String str1 = obj1.toString();
        String str2 = obj2.toString();

        if(str1.compareTo(str2) < 0){
            return -oType;
        }else if(str1.compareTo(str2) == 0){
            return 0;
        }else if(str1.compareTo(str2) > 0){
            return oType;
        }
    }else if((obj1 instanceof Double || obj1 instanceof Float) && (obj2 instanceof Double || obj2 instanceof Float)){
        //浮点型排序
        return doubleCompare(oType, obj1, obj2, twoOrder, twoType);
    }else if((obj1 instanceof Long || obj1 instanceof Integer || obj1 instanceof Short || obj1 instanceof Byte) && 
             (obj2 instanceof Long || obj2 instanceof Integer || obj2 instanceof Short || obj2 instanceof Byte)){
        //整数型排序
        return longCompare(oType, obj1, obj2, twoOrder, twoType);
    }else if((obj1.getClass() != obj2.getClass()) && (obj1 instanceof Number && obj2 instanceof Number)){
        //这种情况可能是,既有整数又有浮点数
        return doubleCompare(oType, obj1, obj2, twoOrder, twoType);
    }
    return 0;
}

/**
 * 整形比较大小
 * @param oType
 * @param obj1
 * @param obj2
 * @param twoOrder
 * @param twoType
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:09:18
 */
private static int longCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    long d1 = Long.parseLong(obj1.toString());
    long d2 = Long.parseLong(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){

        if(twoOrder != null && twoType != null){
            //相等就使用第二字段排序
            return commonOrder(twoOrder, twoType, obj1, obj2, null, null);
        }
        //相同的是否进行交互
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

/**
 * 浮点型比较大小
 * @param oType
 * @param obj1
 * @param obj2
 * @return
 * @author yutao
 * @date 2018年5月24日下午3:09:41
 */
private static int doubleCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    double d1 = Double.parseDouble(obj1.toString());
    double d2 = Double.parseDouble(obj2.toString());
    if(d1 < d2){
        return -oType;
    }else if(d1 == d2){
        if(twoOrder != null && twoType != null){

            //相等就使用第二字段排序
            return commonOrder(twoOrder, twoType, obj1, obj2, null, null);
        }
        return 0;
    }else if(d1 > d2){
        return oType;
    }
    return 0;
}

分析

在JDK7以后,实现Comparable接口后,要满足一下三个特性:
1) 自反性:x,y 的比较结果和 y,x 的比较结果相反。
2) 传递性:x>y,y>z,则 x>z。
3) 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。

而我的代码中,因为有对象属性为null的判断,所以有下面这样的代码:

public static Integer commonOrder(final String orderKey, final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    if (obj1 == null) {
        if(oType < 0){
            return -oType;
        }
        return oType;
    }
    if (obj2 == null) {
        if(oType < 0){
            return oType;
        }
    return -oType;
}
// 以下代码省略。。。

这样的话,是不满足对称性的;
因为必须完善为null的情况:

public static Integer commonOrder(final String orderKey, final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType) {
    //重点注意 
    if(obj1 == null && obj2 == null){
        return 0;
    }
    if (obj1 == null) {
        if(oType < 0){
            return -oType;
        }
        return oType;
    }
    if (obj2 == null) {
        if(oType < 0){
            return oType;
        }
    return -oType;
}
// 以下代码省略。。。

有了上面的代码,就满足对称性了。

参考地址:
https://www.cnblogs.com/wendelhuang/p/7356797.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值