List的多维度排序案例演示~

来源:互联网 发布:读电子书软件 编辑:程序博客网 时间:2024/05/20 18:19

关于List的多维度排序。

日常工作中有很多关于list的排序功能, 看到公司封装的一个比较好的工具类, 这里拿来记录学习下。

public class SortBuilder<T> {    // Never make these public    static final int LEFT_IS_GREATER = 1;    static final int RIGHT_IS_GREATER = -1;    private static final Logger log = LoggerFactory.getLogger(SortBuilder.class);    private List<SortFiled<T>> sortFileds = Lists.newLinkedList();    private Map<String, Method> propertyMethodMap = null;    private boolean nullsFirst;    private boolean nullsLast;    private boolean zerosFirst;    private boolean zerosLast;    private boolean natural;    private Direction naturalDirection;    private SortBuilder() {    }    public static <C> SortBuilder<C> newBuilder(Class clazz) {        SortBuilder<C> sortBuilder = new SortBuilder<>();        PropertyDescriptor[] propertyDescriptor = BeanUtils.getPropertyDescriptors(clazz);        Map<String, Method> propertyMethodMap = new HashMap<>();        for (PropertyDescriptor pd : propertyDescriptor) {            String key = pd.getName();            Method value = pd.getReadMethod();            propertyMethodMap.put(key, value);        }        sortBuilder.propertyMethodMap = propertyMethodMap;        return sortBuilder;    }    /**     * null 排序到最前面     */    public SortBuilder<T> nullsFirst() {        nullsFirst = true;        nullsLast = false;        return this;    }    /**     * null 排序到最后面     */    public SortBuilder<T> nullsLast() {        nullsFirst = false;        nullsLast = true;        return this;    }    /**     * 0 排序到最后面     */    public SortBuilder<T> zerosLast() {        zerosFirst = false;        zerosLast = true;        return this;    }    /**     * 0 排序到最前面     */    public SortBuilder<T> zerosFirst() {        zerosFirst = true;        zerosLast = false;        return this;    }    /**     * 自然排序 {1,5,3,2,4} = {1,2,3,4,5}     */    public SortBuilder<T> natural() {        natural = true;        return this;    }    /**     * 自然排序 {1,5,3,2,4} = {1,2,3,4,5}     */    public SortBuilder<T> natural(Direction direction) {        natural = true;        naturalDirection = direction;        return this;    }    public SortBuilder<T> clear() {        sortFileds.clear();        return this;    }    /**     * 增加一个降序     *     * @param fieldName 属性     */    public SortBuilder<T> addDesc(String fieldName) {        addFieldMethod(fieldName, Direction.DESC);        return this;    }    /**     * 增加一个自定义排序     *     * @param comparator 自定义比较器     */    public SortBuilder<T> addCustom(Comparator<T> comparator) {        sortFileds.add(SortFiled.builder(Direction.CUSTOM, null, comparator));        return this;    }    /**     * 增加一个升序     *     * @param fieldName 属性     */    public SortBuilder<T> addAsc(String fieldName) {        addFieldMethod(fieldName, Direction.ASC);        return this;    }    /**     * 增加一个字段排序模式     *     * @param fieldName 属性     * @param direction 排序方式     */    private SortBuilder<T> addFieldMethod(String fieldName, Direction direction) {        Method method = propertyMethodMap.get(fieldName);        if (method == null) {            log.error("NoSuchMethodException field:{}", fieldName);        } else {            sortFileds.add(SortFiled.<T>builder(direction, method, null));        }        return this;    }    public SortBuilder<T> sortList(List<T> list) {        Collections.sort(list, buildComparator());        return this;    }    private Comparator<T> buildComparator() {        return new Comparator<T>() {            public int compare(T o1, T o2) {                int flag = 0;                if (sortFileds.size() == 0 && natural) {                    flag = compareNatural(o1, o2, naturalDirection);                } else {                    for (SortFiled<T> sortFiled : sortFileds) {                        Method method = sortFiled.getMethod();                        Direction direction = sortFiled.getDirection();                        if (direction == Direction.CUSTOM) {                            flag = sortFiled.getComparator().compare(o1, o2);                        } else {                            flag = this.compare(method, o1, o2, direction);                        }                        if (flag != 0) {                            break;                        }                    }                }                return flag;            }            private int compare(Method method, T left, T right, Direction direction) {                int flag = 0;                try {                    Object leftVal = method.invoke(left);                    Object rightVal = method.invoke(right);                    Class returnType = method.getReturnType();                    if (nullsFirst) {                        flag = compareNulls(returnType, leftVal, rightVal, false, direction);                    } else if (nullsLast) {                        flag = compareNulls(returnType, rightVal, leftVal, true, direction);                    } else {                        flag = compare(returnType, leftVal, rightVal, direction);                    }                } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {                    e.printStackTrace();                }                return flag;            }            private int compareNatural(Object leftVal, Object rightVal, Direction direction) {                int flag;                if (nullsFirst) {                    flag = compareNulls(leftVal, rightVal, false, direction);                } else if (nullsLast) {                    flag = compareNulls(rightVal, leftVal, true, direction);                } else {                    flag = compare(leftVal.getClass(), leftVal, rightVal, direction);                }                return flag;            }            private int compareNulls(Object leftVal, Object rightVal, boolean reverse, Direction direction) {                return compareNulls(leftVal == null ? null : leftVal.getClass(), leftVal, rightVal, reverse, direction);            }            private int compareNulls(Class returnType, Object leftVal, Object rightVal, boolean reverse,                                     Direction direction) {                if (leftVal == rightVal) {                    return 0;                } else if (leftVal == null) {                    return RIGHT_IS_GREATER;                } else if (rightVal == null) {                    return LEFT_IS_GREATER;                } else {                    return reverse ? compare(returnType, rightVal, leftVal, direction) : compare(returnType, leftVal,                            rightVal, direction);                }            }            private int compareZeros(BigDecimal leftNumber, BigDecimal rightNumber, boolean reverse, Direction direction) {                if (leftNumber.compareTo(rightNumber) == 0) {                    return 0;                } else if (leftNumber.compareTo(BigDecimal.valueOf(0)) == 0) {                    return RIGHT_IS_GREATER;                } else if (rightNumber.compareTo(BigDecimal.valueOf(0)) == 0) {                    return LEFT_IS_GREATER;                } else {                    return reverse ? compareNumber(rightNumber, leftNumber, direction) : compareNumber(leftNumber,                            rightNumber, direction);                }            }            private int compareNumber(BigDecimal leftNumber, BigDecimal rightNumber, Direction direction) {                if (leftNumber.compareTo(rightNumber) == 0) {                    return 0;                } else {                    return direction == null || direction == Direction.ASC ? leftNumber.compareTo(rightNumber)                            : rightNumber.compareTo(leftNumber);                }            }            private int compare(Class returnType, Object leftVal, Object rightVal, Direction direction) {                int flag;                if (Number.class.isAssignableFrom(returnType) || returnType == int.class || returnType == long.class                        || returnType == double.class || returnType == float.class) {                    BigDecimal leftNumber = BigDecimal.valueOf(Double.valueOf(leftVal.toString()));                    BigDecimal rightNumber = BigDecimal.valueOf(Double.valueOf(rightVal.toString()));                    if (zerosFirst) {                        flag = compareZeros(leftNumber, rightNumber, false, direction);                    } else if (zerosLast) {                        flag = compareZeros(rightNumber, leftNumber, true, direction);                    } else {                        flag = compareNumber(leftNumber, rightNumber, direction);                    }                } else {                    String methodReturn1 = leftVal.toString();                    String methodReturn2 = rightVal.toString();                    if (direction == null || direction == Direction.ASC) {                        flag = methodReturn1.compareTo(methodReturn2);                    } else {                        flag = methodReturn2.compareTo(methodReturn1);                    }                }                return flag;            }        };    }    /**     * 排序方式:     * <p/>     * ASC:升序,DESC:降序     */    public enum Direction {        ASC, DESC, CUSTOM    }    static class SortFiled<T> {        private Method method;        private Direction direction;        private Comparator<T> comparator;        SortFiled(Direction direction, Method method, Comparator<T> comparator) {            this.method = method;            this.direction = direction;            this.comparator = comparator;        }        @SuppressWarnings("unchecked")        public static <T> SortFiled<T> builder(Direction direction, Method method, Comparator<T> comparator) {            return new SortFiled(direction, method, comparator);        }        public Method getMethod() {            return method;        }        public void setMethod(Method method) {            this.method = method;        }        public Direction getDirection() {            return direction;        }        public void setDirection(Direction direction) {            this.direction = direction;        }        public Comparator<T> getComparator() {            return comparator;        }        public void setComparator(Comparator<T> comparator) {            this.comparator = comparator;        }    }}

使用方法:

@Autowiredprivate SeriesDiagramEntityService seriesDiagramEntityService;@org.junit.Testpublic void testSortBuilder() throws Exception{    List<SeriesDiagramEntity> list = seriesDiagramEntityService.findAll(SeriesDiagramEntity.Fields.status.eq(CommonConstants.DataStatus.PUBLISH).limit(1000));    SortBuilder.<SeriesDiagramEntity>newBuilder(SeriesDiagramEntity.class).addAsc("source").addAsc("displayOrder").addDesc("status").sortList(list);}

使用起来很简单,我们这里写了个unit test来演示。 原理就是直接使用JavaBean中的属性进行asc或者desc的排序展示。

下面来看看它是具体怎么运行的:

  • 首先获取到实体类的属性, 然后添加到propertyMethodMap中。
PropertyDescriptor[] propertyDescriptor = BeanUtils.getPropertyDescriptors(clazz);

获取实体类的属性

  • 然后是将用户自定义的排序字段加入到sortFileds中去:
/** * 增加一个升序 * * @param fieldName 属性 */public SortBuilder<T> addAsc(String fieldName) {    addFieldMethod(fieldName, Direction.ASC);    return this;}/** * 增加一个字段排序模式 * * @param fieldName 属性 * @param direction 排序方式 */private SortBuilder<T> addFieldMethod(String fieldName, Direction direction) {    Method method = propertyMethodMap.get(fieldName);    if (method == null) {        log.error("NoSuchMethodException field:{}", fieldName);    } else {        sortFileds.add(SortFiled.<T>builder(direction, method, null));    }    return this;}

添加排序字段

  • 进行排序
public SortBuilder<T> sortList(List<T> list) {    Collections.sort(list, buildComparator());    return this;}private Comparator<T> buildComparator() {    return new Comparator<T>() {        public int compare(T o1, T o2) {            int flag = 0;            if (sortFileds.size() == 0 && natural) {                flag = compareNatural(o1, o2, naturalDirection);            } else {                for (SortFiled<T> sortFiled : sortFileds) {                    Method method = sortFiled.getMethod();                    Direction direction = sortFiled.getDirection();                    if (direction == Direction.CUSTOM) {                        flag = sortFiled.getComparator().compare(o1, o2);                    } else {                        flag = this.compare(method, o1, o2, direction);                    }                    if (flag != 0) {                        break;                    }                }            }            return flag;        }        private int compare(Method method, T left, T right, Direction direction) {            int flag = 0;            try {                Object leftVal = method.invoke(left);                Object rightVal = method.invoke(right);                Class returnType = method.getReturnType();                if (nullsFirst) {                    flag = compareNulls(returnType, leftVal, rightVal, false, direction);                } else if (nullsLast) {                    flag = compareNulls(returnType, rightVal, leftVal, true, direction);                } else {                    flag = compare(returnType, leftVal, rightVal, direction);                }            } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {                e.printStackTrace();            }            return flag;        }        private int compareNatural(Object leftVal, Object rightVal, Direction direction) {            int flag;            if (nullsFirst) {                flag = compareNulls(leftVal, rightVal, false, direction);            } else if (nullsLast) {                flag = compareNulls(rightVal, leftVal, true, direction);            } else {                flag = compare(leftVal.getClass(), leftVal, rightVal, direction);            }            return flag;        }        private int compareNulls(Object leftVal, Object rightVal, boolean reverse, Direction direction) {            return compareNulls(leftVal == null ? null : leftVal.getClass(), leftVal, rightVal, reverse, direction);        }        private int compareNulls(Class returnType, Object leftVal, Object rightVal, boolean reverse,                                 Direction direction) {            if (leftVal == rightVal) {                return 0;            } else if (leftVal == null) {                return RIGHT_IS_GREATER;            } else if (rightVal == null) {                return LEFT_IS_GREATER;            } else {                return reverse ? compare(returnType, rightVal, leftVal, direction) : compare(returnType, leftVal,                        rightVal, direction);            }        }        private int compareZeros(BigDecimal leftNumber, BigDecimal rightNumber, boolean reverse, Direction direction) {            if (leftNumber.compareTo(rightNumber) == 0) {                return 0;            } else if (leftNumber.compareTo(BigDecimal.valueOf(0)) == 0) {                return RIGHT_IS_GREATER;            } else if (rightNumber.compareTo(BigDecimal.valueOf(0)) == 0) {                return LEFT_IS_GREATER;            } else {                return reverse ? compareNumber(rightNumber, leftNumber, direction) : compareNumber(leftNumber,                        rightNumber, direction);            }        }        private int compareNumber(BigDecimal leftNumber, BigDecimal rightNumber, Direction direction) {            if (leftNumber.compareTo(rightNumber) == 0) {                return 0;            } else {                return direction == null || direction == Direction.ASC ? leftNumber.compareTo(rightNumber)                        : rightNumber.compareTo(leftNumber);            }        }        private int compare(Class returnType, Object leftVal, Object rightVal, Direction direction) {            int flag;            if (Number.class.isAssignableFrom(returnType) || returnType == int.class || returnType == long.class                    || returnType == double.class || returnType == float.class) {                BigDecimal leftNumber = BigDecimal.valueOf(Double.valueOf(leftVal.toString()));                BigDecimal rightNumber = BigDecimal.valueOf(Double.valueOf(rightVal.toString()));                if (zerosFirst) {                    flag = compareZeros(leftNumber, rightNumber, false, direction);                } else if (zerosLast) {                    flag = compareZeros(rightNumber, leftNumber, true, direction);                } else {                    flag = compareNumber(leftNumber, rightNumber, direction);                }            } else {                String methodReturn1 = leftVal.toString();                String methodReturn2 = rightVal.toString();                if (direction == null || direction == Direction.ASC) {                    flag = methodReturn1.compareTo(methodReturn2);                } else {                    flag = methodReturn2.compareTo(methodReturn1);                }            }            return flag;        }    };}

这里排序规则比较多, 大概就是这样。

原创粉丝点击