Life

Friday, May 21, 2021

Collections.sort()用法

        Collections.sort()是java.util.Collections类中的静态方法,提供对集合内元素的排序功能(默认升序),与java.util.Arrays.sort()功能相类似。

sort()有两个overload方法:

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }
public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }
来看一下一般使用sort()的简单用法示例:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;


public class CollectionsSort {
    private static final Logger logger = LoggerFactory.getLogger(CollectionsSort.class);

    public static void main(String[] args) {
        List<Integer> list = new LinkedList<Integer>();
        list.add(5);
        list.add(1);
        list.add(3);
        logger.error("排序前:" + list.toString());
        Collections.sort(list);
        logger.info("排序后:" + list.toString());
    }
}

为什么sort()方法可以直接对List<Integer>直接进行排序呢?
瞅一下java.lang.Integer的定义:
public final class Integer extends Number implements Comparable<Integer>{
public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
}
原来它实现了Comparable接口并override了compareTo()方法,故可调用上文中的第一个overload方法。另外,java.lang.String类同样实现了Comparable接口实现了compareTo()方法,提供按字符顺序(及字符串长度)的排序功能。
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {}
       而在实际应用中,对集合中对象的排序要比Integer复杂的多。 如何实现对复杂对象的排序呢?接下来我们尝试利用java.lang.Integerjava.lang.String的排序特性来实现自定义对象的排序。
       通过Integer的定义我们不难想到可以使用与其相似的定义方法:实现接口Comparable<T>
public class Person implements Comparable<Person>{
    private Integer age;

    private String name;

    public Person(Integer age,String name){
        this.age = age;
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public int compareTo(Person o) {
        int ageResult = this.age.compareTo(o.getAge());//先按年龄
        if(ageResult == 0){
            return this.name.compareTo(o.getName());//后按名称字母顺序
        }
        return ageResult;
    }

    public String toString(){
        return "age:" + this.age + "  name:" + this.name;
    }
}
public class CollectionsSort {
    private static final Logger logger = LoggerFactory.getLogger(CollectionsSort.class);

    public static void main(String[] args) {
        List<Person> list = new LinkedList<Person>();

        Person first = new Person(12,"Jack");
        Person second = new Person(8,"Julian");
        Person third = new Person(12,"Andy");
        Person fourth= new Person(12,"Adler");
        list.add(first);
        list.add(second);
        list.add(third);
        list.add(fourth);
        logger.error("排序前:" + list.toString());
        Collections.sort(list);
        logger.info("排序后:" + list.toString());
    }
}
       通过实现Comparable<T>接口并实现CompareTo()方法提供自定义排序规则,这样我们就实现了一个简单的对自定义对象进行自定义排序的小Demo,在这里先对他们按年龄升序排序,若年龄相等则按名字的字母顺序排序。

       以上是模仿java.lang.Integer类的方式实现的对某对象集合的排序操作,那么如何利用第二个overload的方法实现同样的效果呢?从定义来看,我们只需要创建一个Comparator即可,并override其中的compare()方法,一般习惯使用内部类的方式。

public static void main(String[] args) {
        List<Person> list = new LinkedList<Person>();

        Person first = new Person(12,"Jack");
        Person second = new Person(8,"Julian");
        Person third = new Person(12,"Andy");
        Person fourth = new Person(12,"Adler");
        list.add(first);
        list.add(second);
        list.add(third);
        list.add(fourth);
        logger.info("排序前:" + list.toString());
        Collections.sort(list);
        logger.info("升序:" + list.toString());
        Collections.sort(list, new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                int ageResult = o2.getAge().compareTo(o1.getAge());//年龄降序
                if(ageResult == 0){
                    return o2.getName().compareTo(o1.getName());//名称降序
                }
                return ageResult;
            }
        });
        logger.info("降序:" + list.toString());
    }
这样通过Comparator中的自定义规则完成了对象的降序排列。

      ok,通过以上两种方式,我们都可以实现对某对象的排序功能,那么,ComparableComparator二者有什么分别呢?可以发现,当继承Comparable后,需要实现方法compareTo(),此时我们在就已经定义了对象的自然顺序;而使用Comparator则不同,它创建的是“该类的比较器”,而我可以在不同地方多次定义不同的比较规则。

正如下面所示,完全可以利用Comparator随意定制不同排序规则:

    public static void main(String[] args) {
        List<Person> list = new LinkedList<Person>();

        Person first = new Person(12,"Jack");
        Person second = new Person(8,"Julian");
        Person third = new Person(12,"Andy");
        Person fourth = new Person(12,"Adler");
        list.add(first);
        list.add(second);
        list.add(third);
        list.add(fourth);
        logger.info("排序前:" + list.toString());

        Collections.sort(list, new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                int ageResult = o2.getAge().compareTo(o1.getAge());//年龄降序
                if(ageResult == 0){
                    return o2.getName().compareTo(o1.getName());//名称降序
                }
                return ageResult;
            }
        });
        logger.info("规则一:" + list.toString());

        Collections.sort(list, new Comparator<Person>() {
            public int compare(Person o1, Person o2) {
                int ageResult = o1.getAge().compareTo(o2.getAge());//仅按年龄升序
                return ageResult;
            }
        });
        logger.info("规则二:" + list.toString());
    }

       总的来说,Comparable是一个排序接口,规则总是只有一个;Comparator用于定义用户定制顺序,是比较接口。任何类如果本身不支持排序(即没有实现Comparable接口),我们便可以建立一个“该类的比较器”来进行排序(当然,即便实现Comparable接口同样可以自定义规则)。

版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者Leslie Tien和本文原始地址:
https://leslietien.blogspot.com/2021/05/collectionsSort.html

No comments:

Post a Comment