• 通用实例列表排序实现


    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);
        }
    }
  • 相关阅读:
    select * from a,b探讨
    使用python脚本从数据库导出数据到excel
    git入门
    登录远程服务器脚本
    Ubuntu下python开发环境搭建
    asyncio并发编程
    深入理解python协程
    单例模式的几种实现方式
    MySQL统计百分比结果
    Java查询MySQL数据库指定数据库中所有表名、字段名、字段类型、字段长度、字段描述
  • 原文地址:https://www.cnblogs.com/zhshlimi/p/13468997.html
Copyright © 2020-2023  润新知