JDK8 按List中元素对象的多字段对List进行排序

利用Java8按照元素对象的多字段对List进行排序

实例对象

public class WarningRule implements Serializable {
    private String hour;
    private String content;
    //类型排序字段
    private Integer order;

    public WarningRule() {
    }

    public WarningRule(String hour, Integer order,String content ) {
        this.hour = hour;
        this.content = content;
        this.order = order;
    }

    public String getHour() {
        return hour;
    }

    public void setHour(String hour) {
        this.hour = hour;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }
}

按照hour和order对List<WarningRule>进行排序,hour相同的时候按照order进行排序

Comparator<WarningRule> bya = Comparator.comparing(WarningRule::getHour).reversed();//按照a升序
Comparator<WarningRule> byb = Comparator.comparing(WarningRule::getOrder);//按照b升序
Collections.sort(warningRules,bya.thenComparing(byb));

看一下其中Comparator的源码:

@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);

...

   default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

...

    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

   ...
}

上面只列出了部分代码,可以看出其是一个函数式接口

Comparator<WarningRule> bya = Comparator.comparing(WarningRule::getHour);
我们看一下comparing方法

从上面的源码可以看出这个函数是默认函数,接收的参数是一个函数式接口,即可以传入像例子中的(WarningRule::getHour)类型的方法引用。apply方法接受一个参数返回一个值,即像例子中接收一个WarningRule对象返回其中的hour属性值

返回一个Comparator类型的函数

其返回的Comparator类型的对象利用了lambda表达式,因为Comparator是一个函数式接口,要实现其 

int compare(T o1, T o2);

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

return的是Comparator类型的对象,(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));相当于是Comparator接口的匿名内部类,lambda表达式接收两个参数返回一个int类型的数,就是实现了int compare(T o1, T o2);方法。

而Collections.sort(warningRules,bya.thenComparing(byb));

排序则利用了Comparator的compare方法,看jdk的TimSort类的源码

private static <T> void binarySort(T[] a, int lo, int hi, int start,
                                       Comparator<? super T> c) {
        assert lo <= start && start <= hi;
        if (start == lo)
            start++;
        for ( ; start < hi; start++) {
            T pivot = a[start];

            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                //利用Comparator的compare方法
                if (c.compare(pivot, a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;

            /*
             * The invariants still hold: pivot >= all in [lo, left) and
             * pivot < all in [left, start), so pivot belongs at left.  Note
             * that if there are elements equal to pivot, left points to the
             * first slot after them -- that's why this sort is stable.
             * Slide elements over to make room for pivot.
             */
            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:  a[left + 2] = a[left + 1];
                case 1:  a[left + 1] = a[left];
                         break;
                default: System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }

可以看出排序利用了我们需要实现的Comparator接口的compare方法。

在我们上面所述的实例中compare方法的参数传入的是两个WarningRule类型的对象,

调用compare方法,而compare方法就是(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)),

其中的keyExtractor就是WarningRule::getHour。

接下来看thenComparing方法:

bya.thenComparing(byb)

default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

这个方法接收一个Comparator类型的参数,它先调用自身的compare进行比较,如果返回0说明当前两个对象的这个属性值相等,则调用other的compare 去比较other这个Comparator当时实现compare时传入给compare做参数的对象的属性值

即byb 参数WarningRule的属性值order

如想对对象的一些属性进行降序,例如对hour进行降序,值相同时对order进行升序,可以

 Comparator<WarningRule> bya = Comparator.comparing(WarningRule::getHour).reversed();//按照a降序
 Comparator<WarningRule> byb = Comparator.comparing(WarningRule::getOrder);//按照b升序

看一下reversed()的源码:

default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

继续往下:

public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
        if (cmp == null)
            return reverseOrder();

        if (cmp instanceof ReverseComparator2)
            return ((ReverseComparator2<T>)cmp).cmp;

        return new ReverseComparator2<>(cmp);
    }

继续:

ReverseComparator2(Comparator<T> cmp) {
            assert cmp != null;
            this.cmp = cmp;
        }

        public int compare(T t1, T t2) {
            return cmp.compare(t2, t1);
        }

可以看到将Comparator转化为ReverseCpmparator2,是Collections的内部类。

private static class ReverseComparator2<T> implements Comparator<T>,
        Serializable
    {
        private static final long serialVersionUID = 4374092139857L;

        /**
         * The comparator specified in the static factory.  This will never
         * be null, as the static factory returns a ReverseComparator
         * instance if its argument is null.
         *
         * @serial
         */
        final Comparator<T> cmp;

        ReverseComparator2(Comparator<T> cmp) {
            assert cmp != null;
            this.cmp = cmp;
        }

        public int compare(T t1, T t2) {
            return cmp.compare(t2, t1);
        }

        public boolean equals(Object o) {
            return (o == this) ||
                (o instanceof ReverseComparator2 &&
                 cmp.equals(((ReverseComparator2)o).cmp));
        }

        public int hashCode() {
            return cmp.hashCode() ^ Integer.MIN_VALUE;
        }

        @Override
        public Comparator<T> reversed() {
            return cmp;
        }
    }

看其中的compare方法:

 public int compare(T t1, T t2) {
            return cmp.compare(t2, t1);
        }

比t1和t2的值进行交换,以达到逆序效果。

原创文章 317 获赞 416 访问量 112万+

猜你喜欢

转载自blog.csdn.net/u014082714/article/details/104196357