需求描述
在日常开发工作中,经常需要优先处理集合中的某些对象,而优先处理的原则就是通过对象中的某个字段结合业务场景进行排序,这时候首先想到的就是在对象对应的表结构中添加排序字段,而这涉及到表结构的更改。在一个比较复杂的系统中,一个核心表结构的变化经常是需要涉及大量的代码修改,然后进行回归测试,同时,如果该集合对象是通过外部系统接口调用的方式传进来的话,我们也并不能保证调用者给的集合一定是按照指定字段进行排序的,下面介绍一种不需要改变表结构,借助枚举进行集合自定义排序的方式。
解决方案
1.编写枚举类构造排序对象模型
package com.imodule.finance.biz;
/**
*
* @Description: 该枚举类用来构造应收转实收排序模型
* @author wenhaijin
* @date 2018年4月18日 下午12:39:59
*
*/
public enum T5recvblItemEnum {
LEVY_RECEIVABLE("L100", "LEVY應收",1),
FISR_PRM("0100", "LEVY應收",2),
RE_PRM("0200", "LEVY應收",3),
EDR_LEVY_RECEIVABLE("L400", "保全LEVY應收",4),
ADD_ADDITIONAL_PREMIUM("1000", "增加附加險補費",5),
APL_REPAYMENT("7000", "APL還款",6);
private String value;
private String description;
private int salt;
private T5recvblItemEnum(String value, String description, int salt) {
this.value = value;
this.description = description;
this.salt = salt;
}
public String value() {
return value;
}
public String description() {
return description;
}
public int salt() {
return salt;
}
public static int saltOf(String value) {
for (T5recvblItemEnum itemEnum : T5recvblItemEnum.values()) {
if (itemEnum.value() == value) {
return itemEnum.salt;
}
}
return 100;
}
}
该枚举对应三个属性,排序字段值:value,描述:description,盐值:salt,其中value字段就是集合对象中需要用来排序的字段,通过salt来进行排序
2.2 排序测试
package com.imodule.finance.facade.impl.fincommon;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.imodule.finance.biz.T5recvblItemEnum;
/**
* @ClassName: CollectionSortTest
* @Description: 集合对象排序测试类
* @author 温海金
* @date 2018年7月19日 下午3:30:25
*
*/
public class CollectionSortTest {
public static void main(String[] args) {
List<RecvblBO> RecvblBOs = buildRecvblBOs();
/**
* 对缴费途径进行排序,这边的排序默认按照jdk本身提供的字符顺序进行排序
*/
Collections.sort(RecvblBOs, new Comparator<RecvblBO>() {
@Override
public int compare(RecvblBO o1, RecvblBO o2) {
return o1.getRecvway().compareTo(o2.getRecvway());
}
});
/**
* 按照Item-收付费科目进行排序,排序依据是枚举中定义的权值
*/
Collections.sort(RecvblBOs, new Comparator<RecvblBO>() {
@Override
public int compare(RecvblBO o1, RecvblBO o2) {
return T5recvblItemEnum.saltOf(o1.getItem())-T5recvblItemEnum.saltOf(o2.getItem());
}
});
RecvblBOs.forEach(entity ->{System.out.println(entity);});
}
private static List<RecvblBO> buildRecvblBOs() {
List<RecvblBO> RecvblBOs = new ArrayList<>();
RecvblBOs.add(new RecvblBO("0100","1"));
RecvblBOs.add(new RecvblBO("2200","3"));
RecvblBOs.add(new RecvblBO("9000","3"));
RecvblBOs.add(new RecvblBO("7000","3"));
RecvblBOs.add(new RecvblBO("L100","1"));
RecvblBOs.add(new RecvblBO("0100","3"));
RecvblBOs.add(new RecvblBO("1000","3"));
RecvblBOs.add(new RecvblBO("7000","3"));
RecvblBOs.add(new RecvblBO("L400","3"));
RecvblBOs.add(new RecvblBO("L100","3"));
RecvblBOs.add(new RecvblBO("0100","4"));
RecvblBOs.add(new RecvblBO("0200","5"));
return RecvblBOs;
}
}
/**
* @ClassName: RecvblBO
* @Description: 构造一个应收对象用于排序测试
* @author 温海金
* @date 2018年7月19日 下午3:33:57
*
*/
class RecvblBO{
/**收费科目**/
private String item;
/**缴费方式**/
private String recvway;
public RecvblBO() {
super();
}
public RecvblBO(String item, String recvway) {
super();
this.item = item;
this.recvway = recvway;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getRecvway() {
return recvway;
}
public void setRecvway(String recvway) {
this.recvway = recvway;
}
@Override
public String toString() {
return "RecvblBO [item=" + item + ", recvway=" + recvway + "]";
}
}
以上代码中构造了一个用于测试排序的对象,该对象就两个属性,收费科目item和缴费方式recvway,测试程序中先对缴费方式recvway进行排序,接着再对收费科目item进行排序,两次排序后,打印出集合顺序如下:
从排序结果可以看出,第二次的排序并不会影响第一次排序效果,若要把收费科目为9000的对象排到前面去,只需要调整枚举对象中该科目的权值即可。
3.总结
利用枚举进行集合对象排序可以灵活定义集合对象中根据某个属性进行排序的规则,同时若需要根据多个字段排序,第二次的排序并不会影响第一次的排序结果。
利用这种方式进行排序的优点是无需通过更改数据库表结构增加排序字段,为表结构新增一个排序字段是一个非常繁琐的事情,特别是在一些规模稍大一点的公司,数据库的变更需要提交工单让数据库管理员协助修改,然后在新增该表数据的地方也需要将该数据对应的排序字段置上,这一改动可能还会影响到已上线的一些功能。
这种排序方式的缺点是性能比较慢,因为你需要排序的集合已经从数据库中load出来了,还需要重复遍历该集合,若该集合中对象比较多或者需要对该集合对象根据两个或更多的属性进行排序,又会增加集合的遍历次数,而这一过程是非常耗性能的。所以更好的做法应该是在进行表结构设计的的时候能够考虑得更加周全一些,为需要排序的字段添加索引,若根据某字段排序的依据并非按字母或数字的顺序来定义,还需要预先为该表新增一个字段并添加索引用于后续排序操作,直接在sql语句层面进行排序能够大幅度提高程序性能!