每日一言 Pirates are evil? The Marines are righteous?… Justice will prevail, you say? But of course, it will! Whoever wins this war becomes justice! – Donquixote Doflamingo from One Piece
Comparable接口 在java.lang中定义了Comparable接口,其定义如下:
1 2 3 4 5 package java.lang;public interface Comparable <T> { public int compareTo (T o) ; }
该接口只有一个方法就是comparaTo方法。继承了该接口的类可以通过实现comparable方法来定义该类的比较方法。从而可以使用排序库来方便的实现自定义类的排序问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class Student implements Comparable <Student> { private String name; private int score; public Student (String name, int score) { this .name = name; this .score = score; } @Override public int compareTo (Student other) { return other.score - this .score; } }
compareTo方法 compareTo方法的定义如下:
1 public int compareTo (T o) ;
T o
代表传入进来与之比较的参数
返回值的含义:
返回负数:表示当前对象小于参数对象
返回0:表示当前对象等于参数对象
返回正数:表示当前对象大于参数对象
注意:在实现compareTo方法时,应该注意与 equals
方法的一致性,即 x.equals(y)
为 true
时,x.compareTo(y)
应返回0。
自然排序 在Comparable中实现的比较方法在java中被称为自然排序,这是一个类自身所固有的、默认的比较方式。
实现compareTo方法后,就有许多排序和排序和查找库可以供我们使用:
Arrays类中的排序方法 1 2 3 4 5 6 7 import java.util.Arrays; Arrays.sort(array); Arrays.sort(array, fromIndex, toIndex);
Collections类中的排序方法 1 2 3 4 5 6 7 8 import java.util.Collections;import java.util.List; Collections.sort(list); int index = Collections.binarySearch(list, key);
TreeSet和TreeMap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.TreeSet;import java.util.TreeMap; TreeSet<String> treeSet = new TreeSet <>(); treeSet.add("banana" ); treeSet.add("apple" ); treeSet.add("orange" ); TreeMap<Integer, String> treeMap = new TreeMap <>(); treeMap.put(3 , "Three" ); treeMap.put(1 , "One" ); treeMap.put(2 , "Two" );
PriorityQueue优先队列 1 2 3 4 5 6 7 8 9 10 import java.util.PriorityQueue; PriorityQueue<String> queue = new PriorityQueue <>(); queue.add("banana" ); queue.add("apple" ); queue.add("orange" );String first = queue.poll();
自定义排序 与Comparable 不同,Comparator 是用于自定义排序规则的接口,但是不需要修改被比较的类,而是作为一个独立的比较器。
Comparator 定义 在 java.util
包中,定义如下:
1 2 3 public interface Comparator <T> { int compare (T o1, T o2) ; }
Comparator的静态方法 Java 8开始,Comparator接口提供了多种静态方法来创建和组合比较器:
方法
描述
示例
comparing(Function<T,U>)
根据指定函数提取的键创建比较器
Comparator.comparing(Student::getName)
comparingInt/Long/Double(ToIntFunction)
根据提取的基本类型值创建比较器
Comparator.comparingInt(Student::getScore)
naturalOrder()
返回自然顺序比较器
Comparator.naturalOrder()
reverseOrder()
返回自然顺序的逆序比较器
Comparator.reverseOrder()
nullsFirst(Comparator)
修改比较器使null值排在前面
Comparator.nullsFirst(comparingInt(Student::getScore))
nullsLast(Comparator)
修改比较器使null值排在后面
Comparator.nullsLast(comparing(Student::getName))
reversed()
返回当前比较器的逆序版本
comparing(Student::getScore).reversed()
thenComparing(Comparator)
组合两个比较器,当第一个返回0时使用第二个
comparing(Student::getScore).thenComparing(Student::getName)
thenComparingInt/Long/Double(ToIntFunction)
组合比较器,第二个使用基本类型
comparing(Student::getGrade).thenComparingInt(Student::getScore)
创建Comparator 创建Comparator比较器的方法有很多种,我们从最简单学起:
首先假设我们有一个Person类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Person { private String name; private int age; private double height; public Person (String name, int age, double height) { this .name = name; this .age = age; this .height = height; } public String getName () { return name; } public int getAge () { return age; } public double getHeight () { return height; } @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", height=" + height + '}' ; } }
创建类方式(传统方式) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.Comparator;class PersonNameComparator implements Comparator <Person> { @Override public int compare (Person p1, Person p2) { return p1.getName().compareTo(p2.getName()); } }class PersonAgeDescendingComparator implements Comparator <Person> { @Override public int compare (Person p1, Person p2) { return p2.getAge() - p1.getAge(); } }
使用匿名内部类 1 2 3 4 5 6 7 8 9 import java.util.Comparator; Comparator<Person> ageComparator = new Comparator <Person>() { @Override public int compare (Person p1, Person p2) { return Integer.compare(p1.getAge(), p2.getAge()); } };
使用Lambda表达式 1 2 3 4 5 6 7 8 9 10 import java.util.Comparator; Comparator<Person> ageComparatorLambda = (p1, p2) -> Integer.compare(p1.getAge(), p2.getAge()); Comparator<Person> nameComparatorLambda = (p1, p2) -> p1.getName().compareTo(p2.getName());
使用 Comparator 的静态工厂方法 (Java 8+, 非常推荐,功能强大且易读) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.Comparator; Comparator<Person> compareByAge = Comparator.comparingInt(Person::getAge); Comparator<Person> compareByName = Comparator.comparing(Person::getName); Comparator<Person> compareByHeightDesc = Comparator.comparingDouble(Person::getHeight).reversed(); Comparator<Person> compareByAgeThenName = Comparator.comparingInt(Person::getAge) .thenComparing(Person::getName); Comparator<Person> compareByAgeDescThenName = Comparator.comparingInt(Person::getAge).reversed() .thenComparing(Person::getName); Comparator<Person> compareByAgeNullsFirst = Comparator.nullsFirst(Comparator.comparingInt(Person::getAge)); Comparator<Person> compareByNameNullsLast = Comparator.nullsLast(Comparator.comparing(Person::getName));
使用Comparator
Collections.sort(List <T>
list, Comparator)
Arrays.sort(T[] a, Comparator)
创建有序集合 (TreeSet,TreeMap) 时指定排序规则
1 2 Comparator<Person> byAge = Comparator.comparingInt(Person::getAge); Set<Person> sortedPeople = new TreeSet <>(byAge);