目录
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 异常了。
那怎么解决呢?
-Djava.util.Arrays.useLegacyMergeSort=true
原因是因为JDK7中的Collections.Sort方法实现中,如果两个值是相等的,那么compare方法需要返回0,否则 可能 会在排序时抛错,而JDK6是没有这个限制的。
下面分享一下我,java手把手实现数据库的排序规则
当有多个字段排序的时候,优先以第一个字段排序,如果第一个字段分出顺序就不考虑后面的字段;如果第一个字段相等,就再进行第二个字段的排序,以此类推
eg:a desc,b asc
数据库中表示先以a字段倒序排序,如果a字段拍出顺序,就不再进行排序,如果a字段值相等,就以 b字段升序排序。
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;
}
}
运行结果: