Comparator和Comparable之間的區別
阿新 • • 發佈:2019-02-05
簡介
Comparable介面
該介面對每個實現它的類的物件強加了排序規則。該排序稱之為自然排序(natural ordering)。方法public int compareTo(T o)
是自然排序的排序方法。
實現了comparable介面類的List或者arrays
物件可以通過呼叫以下方法進行排序:
1. Collections#sort(List<T> list) //內部是呼叫第二個方法進行排序
2. Arrays#sort(Object[] a) //演算法是合併排序或二分排序 n^2演算法複雜度
//此外,可以通過將元素新增到一下集合或Map中實現排序
3. SortedMap tm = new TreeMap();
4. SortedSet ts = new TreeSet();
自然排序中,e1.compareTo(e2) == 0
的布林值應該等價於e1.equals(e2)
。注意null
不屬於任何類的例項,故e.compareTo(null)
應丟擲空指標異常,儘管此時e.equals(null)
為false
。
實際上,所有實現comparable的類中方法compareTo
和equals
方法值是等價的。一個特例就是java.math.BigDecimal
。
Comparator介面
通過比較兩個入參得到順序。返回值有三種:
- 1,入參一大於入參二。
- 0,入參相同。
- -1,入參一小於入參二。
實現的類必須保證以下 要求:
sgn(compare(x, y)) == -sgn(compare(y, x))
。暗示著compare(x, y)
拋異常,則compare(y,x)
也拋異常。((compare(x, y) < 0),((compare(y,z) < 0)
暗示著((compare(x,z) < 0)
。compare(x, y)==0
暗示著sgn(compare(x, z))==sgn(compare(y, z))
。
通常情況下,實現Comparator的類並不被嚴格要求要遵循(compare(x, y)==0) == (x.equals(y))
(compare(x, y)==0) == (x.equals(y))
並不成立。
實現Comparator的介面的List或者arrays
物件可以通過呼叫以下方法進行排序:
1. Collections#sort(List<T> list,, Comparator<? super T> c) //內部是呼叫第二個方法進行排序
2. Arrays#sort(Object[] a, Comparator<? super T> c) //演算法是合併排序或二分排序 n^2演算法複雜度
//此外還可以通過將物件加入以下集合或Map實現排序
3. SortedMap tm = new TreeMap(Comparator<? super K> comparator);
4. SortedSet ts = new TreeSet(Comparator<? super K> comparator);
如果有多個比較規則,可以充分利用Comparator
介面的預設方法:
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和Comparable的區別
引數 | Comparable | Comparator |
---|---|---|
排序邏輯 | 排序邏輯必須在待排序物件的類中,故稱之為自然排序 | 排序邏輯在另一個實現 |
實現 | 實現Comparable介面 | 實現Comparator介面 |
排序方法 | int compareTo(Object o1) |
int compare(Object o1,Object o2) |
觸發排序 | Collections.sort(List) | Collections.sort(List, Comparator) |
介面所在包 | java.lang.Comparable |
java.util.Comparator |
栗子
假設我們想要人類先以姓名升序排序,假如姓名一樣則按照年齡排序,則程式碼可以如下:
Person.java
@Data
@NoArgsConstructor
@AllArgsConstructor
/**
* @author hjb
*/
public class Person implements Comparable {
private String name;
private Integer age;
private String mind;
@Override
public int compareTo(Object o) {
Person targetPerson = (Person)o;
int ret = this.name.compareTo(targetPerson.getName());
if(ret == 0){
return Integer.compare(this.age,targetPerson.getAge());
}
if(ret == 0){
return this.getMind().compareTo(targetPerson.getMind());
}
return ret;
}
}
PersonComparator.java
public class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p, Person p2) {
int ret = p.getName().compareTo(p2.getName());
if(ret == 0){
return p.getAge().compareTo(p2.getAge());
}
return ret;
}
}
PersonComparator2.java
public class PersonComparator2 implements Comparator<Person> {
@Override
public int compare(Person p, Person p2) {
return p.getMind().compareTo(p2.getMind());
}
}
TestCompare.java
public class TestComparable {
public static void main(String[] args){
//取資料
List<Person> personList = generatePersonList();
//排序一: 正常
Collections.sort(personList);
print("Collections.sort(list)",personList);
//排序二:發現正常了
PersonComparator pc = new PersonComparator();
PersonComparator2 pc2 = new PersonComparator2();
Collections.sort(personList,pc.thenComparing(pc2));
print("thenComparing",personList);
//排序三:正常
SortedSet<Person> ts = new TreeSet<>(personList);
print("TreeSet",ts);
//排序四:發現某個Person例項被吃掉了,因為TreeSet認為CompareTo為0,則兩個Person例項相同
SortedSet<Person> ts2 = new TreeSet<>(new PersonComparator());
ts2.addAll(personList);
print("TreeSet(Comparator)",ts2);
}
//生成待排序陣列
private static List<Person> generatePersonList() {
List<Person> retList = new ArrayList<>(16);
retList.addAll(
Arrays.asList(
new Person[]{
new Person("erMaZi", 19, "good"),
new Person("liSi", 17, "bad"),
new Person("wangWu", 18, "middle"),
new Person("wangWu", 18, "middla"),
}
)
);
return retList;
}
public static void print(String message,List<Person> personList){
System.out.println(message+":");
for(Person p:personList){
System.out.println(p);
}
System.out.println();
}
public static void print(String message,SortedSet<Person> sortedSet){
System.out.println(message+":");
for(Person p:sortedSet){
System.out.println(p);
}
System.out.println();
}
}
Output
Collections.sort(list):
Person(name=erMaZi, age=19, mind=good)
Person(name=liSi, age=17, mind=bad)
Person(name=wangWu, age=18, mind=middla)
Person(name=wangWu, age=18, mind=middle)
thenComparing:
Person(name=erMaZi, age=19, mind=good)
Person(name=liSi, age=17, mind=bad)
Person(name=wangWu, age=18, mind=middla)
Person(name=wangWu, age=18, mind=middle)
TreeSet:
Person(name=erMaZi, age=19, mind=good)
Person(name=liSi, age=17, mind=bad)
Person(name=wangWu, age=18, mind=middla)
Person(name=wangWu, age=18, mind=middle)
TreeSet(Comparator):
Person(name=erMaZi, age=19, mind=good)
Person(name=liSi, age=17, mind=bad)
Person(name=wangWu, age=18, mind=middla)