Comparable
接口Comparable
是一个排序接口。若一个类实现了Comparable
接口,即代表该类实现了compareTo
方法,该方法规定了该类的对象的比较规则(两个对象如何比较“大小”)。
类通过实现o1.compareTo(o2)
方法来比较o1
和o2
的大小:
o1
大于o2
;o1
小于o2
;o1
等于o2
。Comparator
接口Comparator
是比较器接口。若我们只需要控制某些对象的次序,而类本身并不支持排序(即没有实现Comparable
接口),对于这种情况,我们可以通过建立一个比较器(即关于该类的一个Comparator
接口实现类)来进行排序。
比较器需实现方法compare(T o1, T o2)
,其原理与上面的o1.compareTo(o2)
方法类似,这里就不再描述。
Comparable
接口实现在自身类中,代表默认排序,相当于内部比较器;而Comparator
接口则是为类外实现的一个比较器,相当于外部比较器。
用于比较的自定义Student
类:
public class Student implements Comparable<Student> {
private String name;
private int grade;
public Student() {
}
public Student(String name, int grade) {
this.name = name;
this.grade = grade;
}
public void setName(String name) {
this.name = name;
}
public void setGrade(int grade) {
this.grade = grade;
}
public String getName() {
return name;
}
public int getGrade() {
return grade;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", grade=" + grade +
'}';
}
@Override
@Override
public int compareTo(Student o) {
return this.getGrade() > o.getGrade() ? 1 : this.getGrade() < o.getGrade() ? -1 : this.getName().compareTo(o.getName());
}
}
上述Student
类实现了Comparable
接口,带有默认排序,调试代码如下:
public class Main {
public static void main(String[] args) {
List<Student> arr = new ArrayList<>();
arr.add(new Student("John", 100));
arr.add(new Student("Bob", 75));
arr.add(new Student("Alice", 100));
arr.add(new Student("Jake", 90));
System.out.println(arr);
System.out.println("------------------------");
Collections.sort(arr); //默认排序
System.out.println(arr);
}
}
另外定义一个实现Compartor
接口的比较器如下:
public class StuCompartor implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
}
}
调试代码:
public class StuMain {
public static void main(String[] args) {
List<Student> arr = new ArrayList<>();
arr.add(new Student("John", 100));
arr.add(new Student("Bob", 75));
arr.add(new Student("Alice", 100));
arr.add(new Student("Jake", 90));
System.out.println(arr);
System.out.println("------------------------");
Collections.sort(arr, new StuCompartor());//外部比较器
System.out.println(arr);
}
}
运行结果均如下所示:
[Student{
name='John', grade=100}, Student{
name='Bob', grade=75}, Student{
name='Alice', grade=100}, Student{
name='Jake', grade=90}]
------------------------
[Student{
name='Bob', grade=75}, Student{
name='Jake', grade=90}, Student{
name='Alice', grade=100}, Student{
name='John', grade=100}]
若只排序一次,则可不额外定义比较器,直接利用匿名内部类即可:
Collections.sort(arr, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
}
});
很明显上述写法仍然让人觉得繁琐、复杂,进一步可利用Lambda表达式进行化简:
Collections.sort(arr, (Student o1, Student o2) -> {
return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
});
再进行一些化简(去掉参数类型):
Collections.sort(arr, (o1, o2) -> {
return o1.getGrade() > o2.getGrade() ? 1 : o1.getGrade() < o2.getGrade() ? -1 : o1.getName().compareTo(o2.getName());
});
最终利用方法应用进行化简(同时定义了首选比较量相等时的继续比较依据):
Collections.sort(arr, comparing(Student::getGrade)
.thenComparing(Student::getName));
若需要逆序:
Collections.sort(arr, comparing(Student::getGrade)
.reversed()
.thenComparing(Student::getName));