环境
java:1.7+
前言
公司有个公共的排序方法类,其中,字符串一个方法、日期字符串一个方法、数字一个方法等等;
我觉得这些方法都可以写成一个方法;
下面代码只针对List<Map<String, Object>>
这种方式进行排序
代码
完整代码
下面这段代码有问题 继续看后面的优化代码
/**
* 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
* @param result 结果集
* @param order
* @param orderType -1降序 1升序, 下面代码假设orderType为1
* @return
* @author yutao
* @date 2018年4月24日下午2:20:35
*/
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){
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);
if (obj1 == null) {
if(oType < 0){
return -oType;
}
return oType;
}
if (obj2 == null) {
if(oType < 0){
return oType;
}
return -oType;
}
if(obj1 instanceof Date){
//日期排序
Date date1 = (Date)obj1;
Date date2 = (Date)obj2;
return longCompare(oType, date1.getTime(), date2.getTime());
}else if(obj1 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){
//浮点型排序
return doubleCompare(oType, obj1, obj2);
}else if(obj1 instanceof Long || obj1 instanceof Integer || obj1 instanceof Short || obj1 instanceof Byte){
//整数型排序
return longCompare(oType, obj1, obj2);
}
return 0;
}
});
return result;
}
private static int longCompare(final Integer oType, Object obj1, Object obj2) {
long d1 = Long.parseLong(obj1.toString());
long d2 = Long.parseLong(obj2.toString());
if(d1 < d2){
return -oType;
}else if(d1 == d2){
//相同的是否进行交互
return 0;
}else if(d1 > d2){
return oType;
}
return 0;
}
private static int doubleCompare(final Integer oType, Object obj1, Object obj2) {
double d1 = Double.parseDouble(obj1.toString());
double d2 = Double.parseDouble(obj2.toString());
if(d1 < d2){
return -oType;
}else if(d1 == d2){
return 0;
}else if(d1 > d2){
return oType;
}
return 0;
}
讲解:
①Collections.sort()
的排序规则参考:
https://blog.csdn.net/u013066244/article/details/78997869
② 如果是字符串就用compareTo
方法进行比较;
如果是整数(各种整数)或者Date
,都统一转成long
进行比较。
如果是浮点数,就转成Double
进行比较。
犯的错误
long d1 = Long.parseLong(obj1.toString());
long d2 = Long.parseLong(obj2.toString());
//错误写法
Long d1 = Long.valueOf(obj1.toString());
Long d2 = Long.valueOf(obj2.toString());
//当为Integer或者其他非Long整数时,会报类型转换异常
相同元素不交换带来的后果
上面的代码中,如果元素相同,不会进行交互,那么在进行倒序时可能会与实际想要的结果有偏差。
比如:
假设数据库降序的顺序如下,按照count
的值进行排序:
{
name: "a",
count: 29
},
{
name: "b",
count: 22
},
{
name: "c",
count: 22
}
我们再使用上面的代码,在内存里进行倒序(即升序)。
结果为:
{
name: "b",
count: 22
},
{
name: "c",
count: 22
},
{ name: "a",
count: 29
}
但是可能我们实际想要的结果应该为:
{
name: "c",
count: 22
},
{
name: "b",
count: 22
},
{ name: "a",
count: 29
}
为什么结果会这样呢?因为b和a进行比较count
时,a大,排后面,接下来b和c进行比较,发现相同,上面的代码返回0
,也就是不交换,这时,c就放b的后头,因为算法认为,目前b才是最小的。
针对这样的情况,我们反而希望,相同时,发生交换。
总结
内存排序,不到万不得已才去用,一般数据库排序是最好的!
当需要内存排序时,相同元素是否发生交换需要而外注意。
==============2018-05-18======================start=======
今天遇到这样一个错误:
java.lang.NumberFormatException: For input string: \"0.002091696324526065\"
之所以会报这个错误,是因为其执行到了longCompare()
这个方法,也就是当做整型来处理。
为什么呢?通过打日志我知道了:
class java.lang.Integer---------该值为-------0
class java.lang.Double---------该值为--------0.035
我的数据中,既有Integer
型,又有Double
型,而我上面的代码判断,只判断Obj1
,这样在执行时,就会把两个元素都当做整型
来处理。所以就调了longCompare()
方法。这块需要优化
优化后的代码
/**
* 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
* @param result 结果集
* @param order
* @param orderType -1降序 1升序, 下面代码假设orderType为1
* @return
* @author yutao
* @date 2018年4月24日下午2:20:35
*/
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){
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);
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());
}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);
}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);
}else if((obj1.getClass() != obj2.getClass()) && (obj1 instanceof Number && obj2 instanceof Number)){
//这种情况可能是,既有整数又有浮点数
return doubleCompare(oType, obj1, obj2);
}
return 0;
}
});
return result;
}
private static int longCompare(final Integer oType, Object obj1, Object obj2) {
long d1 = Long.parseLong(obj1.toString());
long d2 = Long.parseLong(obj2.toString());
if(d1 < d2){
return -oType;
}else if(d1 == d2){
//相同的是否进行交互
return 0;
}else if(d1 > d2){
return oType;
}
return 0;
}
private static int doubleCompare(final Integer oType, Object obj1, Object obj2) {
double d1 = Double.parseDouble(obj1.toString());
double d2 = Double.parseDouble(obj2.toString());
if(d1 < d2){
return -oType;
}else if(d1 == d2){
return 0;
}else if(d1 > d2){
return oType;
}
return 0;
}
其实上面的代码应该还可以优化,就是无论是整数还是浮点数,都当做Double
来处理。
遇到的异常
Comparison method violates its general contract!
因为我的代码里没有return
:
... 上面代码省略。。。
else if((obj1.getClass() != obj2.getClass()) &&
(obj1 instanceof Number && obj2 instanceof Number)){
//这种情况可能是,既有整数又有浮点数
doubleCompare(oType, obj1, obj2);//我这里没有写return 也就是自定义排序,不给任何数字
}
==============2018-05-18======================end=======
==============2018-05-24======================start=======
两个字段排序
今天需要一个需求,是要两个字段进行排序,所以我得进行以下修改;
思路:既然是两个字段排序,那么我们就要先第一字段排好序后,相等的话,再进行第二字段排序。
直接上完整的代码了:
/**
* 支持两个字段排序
* @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 result 结果集
* @param order
* @param orderType -1降序 1升序, 下面代码假设orderType为1
* @return
* @author yutao
* @date 2018年4月24日下午2:20:35
*/
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){
return resultOrder(result, order, orderType, null, null);
}
/**
* 公共的排序部分
* @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) {
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;
}
==============2018-05-24======================end=======
==============2018-05-31======================start=======
上面的代码其实并不能实现两个字段排序,逻辑上有点问题。
因为第二次,并没有改变排序字段obj1
|obj2
。
/**
* 支持两个字段排序
* @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) {
//这里加了个判空,原则上,空元素(map)就不该进来
if(o1 == null && o2 == null){
return 0;
}
if (o1 == null) {
if(oType < 0){
return -oType;
}
return oType;
}
if (o2 == null) {
if(oType < 0){
return oType;
}
return -oType;
}
return commonOrder(orderKey, oType, obj1, obj2, twoOrder, twoType, o1, o2);
}
});
return result;
}
/**
* 对结果集进行排序,目前支持日期、字符串、各种整形、各种浮点型
* @param result 结果集
* @param order
* @param orderType -1降序 1升序, 下面代码假设orderType为1
* @return
* @author yutao
* @date 2018年4月24日下午2:20:35
*/
public static List<Map<String, Object>> resultOrder(List<Map<String, Object>> result, String order, Integer orderType){
return resultOrder(result, order, orderType, null, null);
}
/**
* 公共的排序部分
* @param orderKey
* @param oType
* @param obj1
* @param obj2
* @param twoOrder
* @param twoType
* @return
* @author yutao
* @param obj2
* @param obj1
* @param o2
* @param o1
* @date 2018年5月24日下午3:19:37
*/
public static Integer commonOrder(final String orderKey, final Integer oType, String twoOrder, Integer twoType,
Map<String, Object> o1, Map<String, Object> o2) {
Object obj1 = o1.get(orderKey);
Object obj2 = o2.get(orderKey);
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,o1, o2);
}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,o1, o2);
}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, o1, o2);
}else if((obj1.getClass() != obj2.getClass()) && (obj1 instanceof Number && obj2 instanceof Number)){
//这种情况可能是,既有整数又有浮点数
return doubleCompare(oType, obj1, obj2, twoOrder, twoType,o1, o2);
}
return 0;
}
/**
* 整形比较大小
* @param oType
* @param obj1
* @param obj2
* @param twoOrder
* @param twoType
* @return
* @author yutao
* @param o2
* @param o1
* @date 2018年5月24日下午3:09:18
*/
private static int longCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType,
Map<String, Object> o1, Map<String, Object> o2) {
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, null, null, o1, o2);
}
//相同的是否进行交互
return 0;
}else if(d1 > d2){
return oType;
}
return 0;
}
/**
* 浮点型比较大小
* @param oType
* @param obj1
* @param obj2
* @return
* @author yutao
* @param o2
* @param o1
* @date 2018年5月24日下午3:09:41
*/
private static int doubleCompare(final Integer oType, Object obj1, Object obj2, String twoOrder, Integer twoType,
Map<String, Object> o1, Map<String, Object> o2) {
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, null, null, o1, o2);
}
return 0;
}else if(d1 > d2){
return oType;
}
return 0;
}