通用实例列表排序实现
1. ModelsSortHelper
import com.google.common.base.Strings; import org.springframework.beans.BeanUtils; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import lombok.Data; /** * Model列表排序帮助类 */ public class ModelsSortHelper { /** * Model列表排序 * * @param sortStr 排序条件.(必须以 字段名1__asc|desc[,字段名2__asc|desc...] 这样的格式.如 "name_asc,age_desc") * 对应的字段必须实现 Comparable 接口 * @param source 列表 * @param tClass Model类型 * @param <T> Model类型 * @return 排序后的列表 */ public static <T> List<T> sort(String sortStr, List<T> source, Class<T> tClass) { // 转换排序条件列表 List<SortItem> keys = toKeys(sortStr); // 如果没有排序条件,直接返回原列表 if (CollectionUtils.isEmpty(keys)) { return source; } if (CollectionUtils.isEmpty(keys)) { return source; } //根据排序条件列表构建 比较器Comparator<T> Comparator<T> comparator = buildComparator(keys, tClass); // 如果构建失败(字段不存在,字段类型没有实现Comparable等),直接返回原列表 if (comparator == null) { return source; } // 实现排序 return source.stream() .sorted(comparator) .collect(Collectors.toList()); } /** * 转换为排序算法列表 * * @param sortType 排序算法 */ private static List<SortItem> toKeys(String sortType) { if (Strings.isNullOrEmpty(sortType)) { return Collections.emptyList(); } String[] sortItems = sortType.split(","); return Arrays.stream(sortItems) .map(SortItem::new) .collect(Collectors.toList()); } /** * 构建比较器链 * * @param sorts 排序列表 * @param tClass Model类型 * @param <T> Model类型 * @return 比较器 */ private static <T> Comparator<T> buildComparator(List<SortItem> sorts, Class<T> tClass) { // 多个Sort条件,则实现 Comparator的thenComparing Comparator<T> comparator = null; for (SortItem sort : sorts) { Comparator<T> theComparator = buildComparator(sort, tClass); if (theComparator == null) { throw new RuntimeException("创建比较器异常.对应的排序字段为:" + sort.getField()); } // 第一个排序条件为主排序 if (comparator == null) { comparator = theComparator; } else { // 第2个及以后的为辅助排序 comparator = comparator.thenComparing(theComparator); } } return comparator; } /** * 构建单个比较器 * * @param sortItem 排序列表 * @param tClass Model类型 * @param <T> Model类型 * @return 比较器 */ private static <T> Comparator<T> buildComparator(SortItem sortItem, Class<T> tClass) { String field = sortItem.getField(); return (T o1, T o2) -> sortItem.isAsc() ? getVal(o1, tClass, field).compareTo(getVal(o2, tClass, field)) : getVal(o2, tClass, field).compareTo(getVal(o1, tClass, field)); } /** * 获取字段对应的值的方法 * @param instance 比较实例 * @param tClass Model类型 * @param field 比较字段 * @param <T> Model类型 * @return 返回一个Comparable 类型的值 */ private static <T> Comparable getVal(T instance, Class<T> tClass, String field) { // BeanUtils 已缓存到一个Map里 PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(tClass, field); Method readMethod = propertyDescriptor.getReadMethod(); try { Object val = readMethod.invoke(instance); if (val instanceof Comparable) { return (Comparable) val; } } catch (Exception ex) { throw new RuntimeException("配置排序字段异常-1"); } throw new RuntimeException("配置排序字段异常-3"); } @Data static class SortItem { private String field; private String type; public SortItem(String sort) { String[] arr = sort.split("__"); Assert.isTrue(arr.length == 2); Assert.isTrue(!Strings.isNullOrEmpty(arr[0]) && !Strings.isNullOrEmpty(arr[1])); Assert.isTrue("asc".equalsIgnoreCase(arr[1]) || "desc".equalsIgnoreCase(arr[1])); field = arr[0]; type = arr[1]; } public boolean isAsc() { return "asc".equalsIgnoreCase(type); } } }
2.测试
import java.math.BigDecimal; import java.time.LocalDateTime; import lombok.Builder; import lombok.Data; /** * Created by zhangjy on 2020/8/10. */ @Data @Builder public class StudentModel { private int id; private String name; private BigDecimal score;// name; private LocalDateTime birthday; }
import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; /** * Created by zhangjy on 2020/8/10. */ public class ModelSortTest { static final List<StudentModel> STUDENT_MODELS = new ArrayList<>(); static { StudentModel studentModel1 = StudentModel.builder() .id(100) .name("张三") .score(BigDecimal.TEN) .birthday(LocalDateTime.of(2001,1,1,0,0)) .build(); StudentModel studentModel2 = StudentModel.builder() .id(101) .name("李四") .birthday(LocalDateTime.of(1999,1,1,0,0)) .score(BigDecimal.ZERO) .build(); StudentModel studentModel3 = StudentModel.builder() .id(102) .name("王五") .score(BigDecimal.ONE) .birthday(LocalDateTime.of(2003,1,1,0,0)) .build(); StudentModel studentModel4 = StudentModel.builder() .id(103) .name("麻六") .score(BigDecimal.TEN) .birthday(LocalDateTime.of(2001,1,1,0,0)) .build(); STUDENT_MODELS.add(studentModel1); STUDENT_MODELS.add(studentModel2); STUDENT_MODELS.add(studentModel3); STUDENT_MODELS.add(studentModel4); } public static void main(String[] args) { String sortStr = "score__desc,id__desc"; List<StudentModel> result = ModelsSortHelper.sort(sortStr, STUDENT_MODELS, StudentModel.class); System.out.println("按分数降序,id降序排列如下:"); System.out.println(result); sortStr = "birthday__asc,name__desc"; result = ModelsSortHelper.sort(sortStr, STUDENT_MODELS, StudentModel.class); System.out.println("按生日升序,名字降序排列如下:"); System.out.println(result); } }