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> resultOrder(List> 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>() {
        @Override
        public int compare(Map o1, Map 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

你可能感兴趣的:(Java)