java实现数据库排序功能|compare排序出现IllegalArgumentException: Comparison method violates its general contract

简介: java实现数据库排序功能|compare排序出现IllegalArgumentException: Comparison method violates its general contract

一、前言

java实现排序的时候,有时候会出现异常java.lang.IllegalArgumentException: Comparison method violates its general contract,


报这个异常的原因是代码里没有考虑对象o1和对象o2为Null的情况,


即当o1与o2都为null时两者大小如何判定呢;


当o1为null但o2不为null时两者大小又如何判定了呢,


同理当o2为null但o1不为null时两者大小又如何判定呢


所以代码里没有考虑上述情况的时候,就会出现Comparison method violates its general contract 异常了。


那怎么解决呢?


二、解决方法

第一种方法是在jvm启动参数中加上配置

-Djava.util.Arrays.useLegacyMergeSort=true

原因是因为JDK7中的Collections.Sort方法实现中,如果两个值是相等的,那么compare方法需要返回0,否则 可能 会在排序时抛错,而JDK6是没有这个限制的。

第二种方法是在代码中实现

下面分享一下我,java手把手实现数据库的排序规则


当有多个字段排序的时候,优先以第一个字段排序,如果第一个字段分出顺序就不考虑后面的字段;如果第一个字段相等,就再进行第二个字段的排序,以此类推


eg:a desc,b asc


数据库中表示先以a字段倒序排序,如果a字段拍出顺序,就不再进行排序,如果a字段值相等,就以 b字段升序排序。


java怎么实现上述功能呢?

java实现代码

我们先定义规则:


可以传入排序规则,多个规则用英文逗号分隔,冒号后面跟num还是text表示是用数字排序还是用字符串排序;如果冒号后面不跟num或者text,默认用字符串排序


eg:a.asc:num,b.desc,c.asc:text


表示a字段用数字类型升序排序,如果相等再用b字段字符串倒序排序,最后用c字段字符串升序排序

实现数据库排序的代码如下

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class Testaaa {
    /**
     * 大于SORT_SIZE要排序
     */
    static Integer SORT_SIZE = 1;
    /**
     * 倒序排序
     */
    static String SORT_DESC = "desc";
    /**
     * 合并计算方式
     */
    static String COMBINECALC_FLAG = "1";
    /**
     * 该字段属于什么类型,数字还是字符串
     */
    static String TEXT_TYPE = "num";
    /**
     * 绝对值
     */
    static String TEXT_TYPE_ABS = "abs";
    /**
     * 冒号分隔符
     */
    static String COLON_SEPARATOR = ":";
    public static void main(String[] args) {
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>();
        map1.put("map","map1");
        map1.put("c","111");
        map1.put("d",null);
        list.add(map1);
        Map<String, Object> map2 = new HashMap<>();
        map2.put("map","map2");
        map2.put("c","333");
        map2.put("d","bbb");
        list.add(map2);
        Map<String, Object> map3 = new HashMap<>();
        map3.put("map","map3");
        map3.put("c","444");
        map3.put("d","aaa");
        list.add(map3);
        Map<String, Object> map4 = new HashMap<>();
        map4.put("map","map4");
        map4.put("c","222");
        map4.put("d",null);
        list.add(map4);
        Map<String, Object> map5 = new HashMap<>();
        map5.put("map","map5");
        map5.put("c",null);
        map5.put("d","ccc");
        list.add(map5);
        Map<String, Object> map6 = new HashMap<>();
        map6.put("map","map6");
        map6.put("c","444");
        map6.put("d",null);
        list.add(map6);
        Map<String, Object> map7 = new HashMap<>();
        map7.put("map","map7");
        map7.put("c",null);
        map7.put("d","cca");
        list.add(map7);
        Map<String, Object> map8 = new HashMap<>();
        map8.put("map","map8");
        map8.put("c",null);
        map8.put("d",null);
        list.add(map8);
        Map<String, Object> map9 = new HashMap<>();
        map9.put("map","map9");
        map9.put("c","555");
        map9.put("d",null);
        list.add(map9);
        Map<String, Object> map10 = new HashMap<>();
        map10.put("map","map10");
        map10.put("c","444");
        map10.put("d","eee");
        list.add(map10);
        String orderRule="c.desc:num,d.asc";
        sortResultList(orderRule, list);
        System.out.println(JSON.toJSONString(list, SerializerFeature.WriteMapNullValue));
    }
    private static void sortResultList(String orderRule, List<Map<String, Object>> resultList) {
        if (CollectionUtils.isNotEmpty(resultList) && StringUtils.isNotBlank(orderRule)) {
            List<String> ruleList = Arrays.asList(orderRule.split(","));
            // 对外部进行排序
            if (resultList.size() > SORT_SIZE) {
                sortList(ruleList, resultList);
            }
            // 对内部children进行排序
            for (Map<String, Object> stringObjectMap : resultList) {
                List<Map<String, Object>> children = (List<Map<String, Object>>) stringObjectMap.get("children");
                if (CollectionUtils.isNotEmpty(children) && children.size() > SORT_SIZE) {
                    sortList(ruleList, children);
                }
            }
        }
    }
    public static void sortList(List<String> ruleList, List<Map<String, Object>> result) {
        Collections.sort(result, new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> str1, Map<String, Object> str2) {
                return compareRule(ruleList, 0, str1, str2);
            }
        });
    }
    /**
     * 递归排序
     * @param ruleList
     * @param i
     * @param str1
     * @param str2
     * @return
     */
    private static Integer compareRule(List<String> ruleList, Integer i, Map<String, Object> str1, Map<String, Object> str2) {
        int sort = 0;
        int no = i;
        if (i < ruleList.size()) {
            // 排序规则:eg:date.asc:num,id.desc:text
            String rule = ruleList.get(i);
            // data asc:num 或者 id desc
            String[] typeArray = rule.split("[.]");
            if (str2.containsKey(typeArray[0]) && str2.get(typeArray[0]) != null
                    && StringUtils.isNotBlank(str2.get(typeArray[0]).toString())
                    && str1.containsKey(typeArray[0]) && str1.get(typeArray[0]) != null
                    && StringUtils.isNotBlank(str1.get(typeArray[0]).toString())) {
                // 该字段排序是用什么类型:数字还是字符串
                String[] textType = new String[2];
                if (typeArray[1].indexOf(COLON_SEPARATOR) != -1) {
                    textType = typeArray[1].split("[:]");
                } else {
                    textType[0] = typeArray[1];
                    textType[1] = "text";
                }
                // 按数字排序
                if (StringUtils.isNotBlank(textType[1]) && TEXT_TYPE.equalsIgnoreCase(textType[1])) {
                    if (SORT_DESC.equalsIgnoreCase(textType[0])) {
                        sort = Double.valueOf(str2.get(typeArray[0]).toString()).compareTo(Double.valueOf(str1.get(typeArray[0]).toString()));
                    } else {
                        sort = Double.valueOf(str1.get(typeArray[0]).toString()).compareTo(Double.valueOf(str2.get(typeArray[0]).toString()));
                    }
                } else if (StringUtils.isNotBlank(textType[1]) && TEXT_TYPE_ABS.equalsIgnoreCase(textType[1])) {
                    // 绝对值排序
                    double val1;
                    double val2;
                    if (SORT_DESC.equalsIgnoreCase(textType[0])) {
                        val1 = Double.parseDouble(str2.get(typeArray[0]).toString());
                        val2 = Double.parseDouble(str1.get(typeArray[0]).toString());
                    } else {
                        val1 = Double.parseDouble(str1.get(typeArray[0]).toString());
                        val2 = Double.parseDouble(str2.get(typeArray[0]).toString());
                    }
                    sort = Double.compare(Math.abs(val1), Math.abs(val2));
                } else {
                    // 字符串排序
                    // 倒序
                    if (SORT_DESC.equalsIgnoreCase(textType[0])) {
                        sort = str2.get(typeArray[0]).toString().compareTo(str1.get(typeArray[0]).toString());
                    } else {
                        // 正序
                        sort = str1.get(typeArray[0]).toString().compareTo(str2.get(typeArray[0]).toString());
                    }
                }
                // 如果第一个字段相等,按第二个字段排序
                if (sort == 0) {
                    no = no + 1;
                    sort = compareRule(ruleList, no, str1, str2);
                } else {
                    return sort;
                }
            } else {
                // 将null值往后面排
                if (
                    // 第一个值为null,第二个值不为null的情况
                        ((!str1.containsKey(typeArray[0])) ||
                                (str1.containsKey(typeArray[0]) && str1.get(typeArray[0]) == null) ||
                                (str1.containsKey(typeArray[0]) && str1.get(typeArray[0]) != null && StringUtils.isBlank(str1.get(typeArray[0]).toString()))) &&
                                (str2.containsKey(typeArray[0]) && str2.get(typeArray[0]) != null && StringUtils.isNotBlank(str2.get(typeArray[0]).toString()))) {
                    sort = 1;
                } else if (
                    // 第一个值不为null,第二个值为null的情况
                        ((!str2.containsKey(typeArray[0])) ||
                                (str2.containsKey(typeArray[0]) && str2.get(typeArray[0]) == null) ||
                                (str2.containsKey(typeArray[0]) && str2.get(typeArray[0]) != null && StringUtils.isBlank(str2.get(typeArray[0]).toString()))) &&
                                (str1.containsKey(typeArray[0]) && str1.get(typeArray[0]) != null && StringUtils.isNotBlank(str1.get(typeArray[0]).toString()))) {
                    sort = -1;
                } else {
                    // 第一个值和第二个值都为null情况
                    sort = 0;
                }
                // 如果第一个字段相等,按第二个字段排序
                if (sort == 0) {
                    no = no + 1;
                    sort = compareRule(ruleList, no, str1, str2);
                } else {
                    return sort;
                }
            }
        }
        return sort;
    }
}

运行结果:

相关文章
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
605 211
|
JavaScript Java 微服务
现代化 Java Web 在线商城项目技术方案与实战开发流程及核心功能实现详解
本项目基于Spring Boot 3与Vue 3构建现代化在线商城系统,采用微服务架构,整合Spring Cloud、Redis、MySQL等技术,涵盖用户认证、商品管理、购物车功能,并支持Docker容器化部署与Kubernetes编排。提供完整CI/CD流程,助力高效开发与扩展。
1234 64
|
存储 数据可视化 Java
Java Stream API 的强大功能
Java Stream API 是 Java 8 引入的重要特性,它改变了集合数据的处理方式。通过声明式语法,开发者可以更简洁地进行过滤、映射、聚合等操作。Stream API 支持惰性求值和并行处理,提升了代码效率和可读性,是现代 Java 开发不可或缺的工具。
252 0
Java Stream API 的强大功能
|
前端开发 JavaScript Java
Java 项目实战城市公园信息管理系统开发流程与实用功能实现指南
本系统基于Java开发,采用Spring Boot后端框架与Vue.js前端框架,结合MySQL数据库,构建了一个高效的城市公园信息管理系统。系统包含管理员、用户和保洁人员三大模块,涵盖用户管理、园区信息查询、订票预约、服务管理等功能,提升公园管理效率与服务质量。
349 6
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
543 2
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
556 14
|
Java API
Java API中Math类功能全景扫描
在实际使用时,这些方法的精确度和性能得到了良好的优化。当处理复杂数学运算或高精度计算时,`Math`类通常是足够的。然而,对于非常精细或特殊的数学运算,可能需要考虑使用 `java.math`包中的 `BigDecimal`类或其他专业的数学库。
312 11
|
机器学习/深度学习 算法 Java
Java 大视界 -- Java 大数据机器学习模型在生物信息学基因功能预测中的优化与应用(223)
本文探讨了Java大数据与机器学习模型在生物信息学中基因功能预测的优化与应用。通过高效的数据处理能力和智能算法,提升基因功能预测的准确性与效率,助力医学与农业发展。