在Java开发中,Map是常用的数据结构,当我们需要存储多个对象的属性集合时,经常会使用List<Map<String, Object>>这样的结构。如果业务要求对列表中的数据按照多个字段排序,且排序的字段和升降序规则可以动态配置,就需要自己实现对应的排序逻辑。

基础排序思路
Java中的Collections.sort方法或者List的sort方法支持传入自定义的比较器Comparator,我们可以通过构建动态的比较器来实现多字段排序。核心逻辑是:先按照第一个排序字段比较,如果第一个字段相等,再按照第二个字段比较,以此类推,同时每个字段可以单独指定升降序。
动态排序规则定义
首先我们需要定义一个排序规则的类,用来存储每个排序字段的名称和对应的排序方向,方便外部动态传入规则:
import java.util.Objects;
/**
* 排序规则定义类
*/
public class SortRule {
// 排序字段名
private String fieldName;
// 是否升序,true为升序,false为降序
private boolean asc;
public SortRule(String fieldName, boolean asc) {
this.fieldName = fieldName;
this.asc = asc;
}
public String getFieldName() {
return fieldName;
}
public boolean isAsc() {
return asc;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SortRule sortRule = (SortRule) o;
return asc == sortRule.asc && Objects.equals(fieldName, sortRule.fieldName);
}
@Override
public int hashCode() {
return Objects.hash(fieldName, asc);
}
}
动态多字段排序实现
接下来我们实现核心的排序方法,接收Map列表和动态排序规则列表,构建复合比较器完成排序:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class MapSortUtil {
/**
* 基于动态排序规则对Map列表进行多字段排序
* @param mapList 待排序的Map列表,每个Map的value类型需要支持比较(实现Comparable接口)
* @param sortRules 动态排序规则列表,按顺序生效
*/
public static void sortMapList(List<Map<String, Object>> mapList, List<SortRule> sortRules) {
if (mapList == null || mapList.isEmpty() || sortRules == null || sortRules.isEmpty()) {
return;
}
// 构建复合比较器
Comparator<Map<String, Object>> comparator = null;
for (SortRule rule : sortRules) {
Comparator<Map<String, Object>> currentComparator = (m1, m2) -> {
Object v1 = m1.get(rule.getFieldName());
Object v2 = m2.get(rule.getFieldName());
// 处理字段值为null的情况,null值统一放到最后
if (v1 == null && v2 == null) {
return 0;
}
if (v1 == null) {
return rule.isAsc() ? 1 : -1;
}
if (v2 == null) {
return rule.isAsc() ? -1 : 1;
}
// 假设字段值实现了Comparable接口,直接比较
Comparable<Object> cv1 = (Comparable<Object>) v1;
int compareResult = cv1.compareTo(v2);
// 如果是降序,反转比较结果
return rule.isAsc() ? compareResult : -compareResult;
};
if (comparator == null) {
comparator = currentComparator;
} else {
// 多个规则时,前一个规则相等再走下一个规则
comparator = comparator.thenComparing(currentComparator);
}
}
// 执行排序
mapList.sort(comparator);
}
public static void main(String[] args) {
// 构造测试数据
List<Map<String, Object>> dataList = new ArrayList<>();
// 添加第一条数据
Map<String, Object> data1 = new java.util.HashMap<>();
data1.put("name", "张三");
data1.put("age", 20);
data1.put("score", 85.5);
dataList.add(data1);
// 添加第二条数据
Map<String, Object> data2 = new java.util.HashMap<>();
data2.put("name", "李四");
data2.put("age", 22);
data2.put("score", 90.0);
dataList.add(data2);
// 添加第三条数据
Map<String, Object> data3 = new java.util.HashMap<>();
data3.put("name", "王五");
data3.put("age", 20);
data3.put("score", 85.5);
dataList.add(data3);
// 添加第四条数据,age字段为null
Map<String, Object> data4 = new java.util.HashMap<>();
data4.put("name", "赵六");
data4.put("age", null);
data4.put("score", 78.0);
dataList.add(data4);
// 定义动态排序规则:先按age升序,再按score降序
List<SortRule> sortRules = new ArrayList<>();
sortRules.add(new SortRule("age", true));
sortRules.add(new SortRule("score", false));
System.out.println("排序前数据:");
for (Map<String, Object> item : dataList) {
System.out.println(item);
}
// 执行排序
sortMapList(dataList, sortRules);
System.out.println("n排序后数据:");
for (Map<String, Object> item : dataList) {
System.out.println(item);
}
}
}
实现说明
上述实现中需要注意几个点:
- 字段值的null处理:我们将null值统一放到排序的最后,避免空指针异常,也可以根据实际需求调整null值的排序位置。
- 字段类型要求:默认实现假设Map中的字段值实现了
Comparable接口,如果是自定义类型,需要让该类型实现Comparable接口,或者修改比较逻辑添加自定义的类型比较方式。 - 规则顺序:排序规则列表的顺序就是多字段排序的优先级顺序,先传入的规则优先级更高。
扩展场景
如果排序规则需要支持更复杂的逻辑,比如字段是字符串类型需要按照长度排序,或者需要自定义比较逻辑,可以在SortRule类中添加自定义比较器的属性,在构建排序逻辑时优先使用自定义比较器,从而实现更灵活的动态排序能力。