Collections.sort(List<T>, Comparator<? super T>)方法示例

70

可能重复:
使用多个键排序Java对象

我找不到使用这个方法的任何示例,所有示例都将第二个参数设置为“null”。 据说这个方法可以按照多个标准对类进行排序,但没有找到任何例子。

public class Student implements Comparable<Student> {
String name;
int age;

public Student(String name, int age) {
    this.name = name;
    this.age = age;
}

@Override
public String toString() {
    return name + ":" + age;
}

@Override
public int compareTo(Student o) {
    Integer myAge = age;
    Integer oAge = o.age;
    return myAge.compareTo(oAge);
}

如果我想根据学生的姓名和年龄对学生列表进行排序,我该如何使用Collections sort(List, Comparator)方法来实现?

4个回答

127

在您现有的学生类的基础上,这是我通常的做法,特别是当我需要多个比较器时。

public class Student implements Comparable<Student> {

    String name;
    int age;

    public Student(String name, int age) {
       this.name = name;
       this.age = age;
    }

    @Override
    public String toString() {
        return name + ":" + age;
    }

    @Override
    public int compareTo(Student o) {
        return Comparators.NAME.compare(this, o);
    }


    public static class Comparators {

        public static Comparator<Student> NAME = new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.name.compareTo(o2.name);
            }
        };
        public static Comparator<Student> AGE = new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.age - o2.age;
            }
        };
        public static Comparator<Student> NAMEANDAGE = new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int i = o1.name.compareTo(o2.name);
                if (i == 0) {
                    i = o1.age - o2.age;
                }
                return i;
            }
        };
    }
}

使用方法:

List<Student> studentList = new LinkedList<>();
Collections.sort(studentList, Student.Comparators.AGE);

编辑

自从Java 8发布以来,使用lambda表达式可以大大简化内部类Comparators的代码。Java 8还引入了一个新的方法thenComparing用于Comparator对象,当嵌套比较器时,它可以省去手动检查每个比较器的需要。以下是考虑到这些更改的Student.Comparators类的Java 8实现。

public static class Comparators {
    public static final Comparator<Student> NAME = (Student o1, Student o2) -> o1.name.compareTo(o2.name);
    public static final Comparator<Student> AGE = (Student o1, Student o2) -> Integer.compare(o1.age, o2.age);
    public static final Comparator<Student> NAMEANDAGE = (Student o1, Student o2) -> NAME.thenComparing(AGE).compare(o1, o2);
}

谢谢,JAVA 8的创新特性确实使得一些复杂的代码变得容易了! - Smit

72

这可能是最简单的方法 -

Collections.sort(listOfStudent,new Comparator<Student>(){
                     public int compare(Student s1,Student s2){
                           // Write your logic here.
                     }});

使用Java 8(Lambda表达式) -

listOfStudent.sort((s1, s2) -> s1.age - s2.age); 

这个逻辑是否最好用预先构建的解决方案来替代,比如Apache的CompareToBuilder? - IgorGanapolsky
2
@IgorGanapolsky 是的和不是。当你的逻辑非常简单时,答案是肯定的。而当你的比较逻辑很复杂时,答案就是否定的了。 :) - Subhrajyoti Majumder
s1.age - s2.age 的原因是什么? - mbj
2
@s1.age - s2.age 的翻译是按年龄值升序排序元素。 - immukul

14

您可能想要这样的内容:

Collections.sort(students, new Comparator<Student>() {
                     public int compare(Student s1, Student s2) {
                           if(s1.getName() != null && s2.getName() != null && s1.getName().comareTo(s1.getName()) != 0) {
                               return s1.getName().compareTo(s2.getName());
                           } else {
                             return s1.getAge().compareTo(s2.getAge());
                          }
                      }
);

这将首先按姓名对学生进行排序。如果有姓名缺失,或者两个学生姓名相同,则按照他们的年龄进行排序。


如果只有其中一个名称为空,似乎不稳定。 - Qwertiy

3
要使用Collections sort(List,Comparator),您需要创建一个实现Comparator接口的类,并在其中编写compare()的代码,详见Comparator Interface
您可以像这样操作:
class StudentComparator implements Comparator
{
    public int compare (Student s1 Student s2)
    {
        // code to compare 2 students
    }
}

要进行排序,请执行以下操作:

 Collections.sort(List,new StudentComparator())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接