Comparable和Comparator兩種比較器詳解

本篇博文環境是jdk1.8。

【1】java.lang.Comparable

Comparable,翻譯一下爲可比較的。從漢語詞義來看,通常是表明對象特性,即該對象是可比較的。實現了該接口的類的實例對象就可以進行自然排序,該實例對象的集合或者數組就可以使用Collections.sort或Arrays.sort方法進行自然排序。

接口源碼如下:

package java.lang;
import java.util.*;

public interface Comparable<T> {
    int compareTo(T var1);
}

實現了該接口的類實例對象可以作爲SortedMap的key或者SortedSet的元素,而無需使用一個額外的比較器-Comparator。

強烈推薦自然排序結果與equals方法保持一致(雖然不是一定的),即自然排序時兩個對象相等條件爲 e1.equals(e2)返回true時,e1.compareTo(e2) == 0。另外需要注意的是null對象不是任何一個類的實例對象,所以e.compareTo(null)應該拋出NullPointerException,即使e.equals(null)返回false。

如果compareTo方法與對象的equals方法比較結果不一致時 ,那麼在使用SortedMap、SortedSet這類沒有明確比較器的集合時就會很奇怪。尤其是將會違反集合的基本約定–根據equals方法判斷集合元素是否相等。

然而並不 嚴格要求(x.compareTo(y)==0) == (x.equals(y))。一般說來,任何違背這個條件的實現都應該明確指出這一事實情況。

實際上,實現Comparable的所有Java核心類都具有與equals一致的自然順序。一個例外是java.math.BigDecimal,其自然順序等同於具有相同值和不同精度(例如4.0和4.00)的大十進制對象。

int compareTo(T var1);方法會比較兩個實例對象,0表示相等,正數表示大於,負數表示小於。

實現該方法一定要注意以下事項:

  • 必須保證sgn(x.compareTo(y)) ==-sgn(y.compareTo(x))
  • 必須保證比較的順序關係是可傳遞的,如果x.compareTo(y)>0 而且y.compareTo(z)>0 則x.compareTo(z)>0。
  • 如果存在x.compareTo(y)=0,則對於 z 而言,存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))。

Comparable 的典型實現:

  • BigDecimal、BigInteger 以及所有的數值型對應的包裝類:按它們對應的數值大小進行比較
  • Character:按字符的 unicode值來進行比較
  • Boolean:true 對應的包裝類實例大於 false 對應的包裝類實例
  • String:按字符串中字符的 unicode 值進行比較
  • Date、Time:後邊的時間、日期比前面的時間、日期大

【2】java.util.Comparator

首先第一點不同的就是,包不同了!Comparable是在java.lang包中,而Comparator是在java.util中。
在這裏插入圖片描述

第二點不同的是Comparator被顯示作爲一個函數式接口,其上有@FunctionalInterface註解。其只有兩個抽象方法(compare和equals)但是提供了很多默認方法和靜態方法。

Java 8中允許接口中包含具有具體實現的方法,該方法稱爲“默認方法”,默認方法使用default關鍵字修飾。而且Default方法只在接口中被允許使用。
Java8 中,接口中允許添加靜態方法,可以直接被使用。

package java.util;

import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;

@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);

	boolean equals(Object obj);

 	default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

//...
}

在這裏插入圖片描述

Comparator比較器可以被使用在Collections.sort或 Arrays.sort方法中允許對排序順序進行精確控制。Comparator同樣可以被使用在SortedSet、SortedMap以及對其他自身沒有自然排序屬性的實例對象上。

同Comparable一樣,Comparator的compare方法返回結果應該與equals方法返回結果保持一致。即,c.compare(e1, e2)==0時e1.equals(e2)。

不過建議謹慎使用Comparator,因爲該比較器可以強制排序與使用equals方法排序集合不一致。

實現Comparator的compare方法需要保證以下幾點:

  • 必須保證sgn(compare(x, y)) ==-sgn(compare(y, x))
  • 必須保證比較的順序關係是可傳遞的,如果compare(x,y)>0 而且compare(y,z)>0 則 compare(x,z)>0。
  • 如果存在 compare(x,y)=0,則對於 z 而言,存在 compare(x, z)==compare(y, z)。

強烈推薦compare(x,y)方法返回結果與x.equals(y)方法返回結果保持一致。然而並不 嚴格要求(compare(x, y)==0) == (x.equals(y))。一般說來,任何違背這個條件的 Comparator 實現都應該明確指出這一事實情況。

使用實例如下

@Test
	public void test4(){
		List<Integer> integers=new ArrayList<>();
		integers.add(1);
		integers.add(2);
		integers.add(3);
		//匿名內部類
		integers.sort(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1.compareTo(o2);
			}
		});
		//lambda表達式
		integers.sort((o1,o2)->o1.compareTo(o2));
//		Comparator<Integer> integerComparator = Integer::compareTo;
		//方法引用
		integers.sort(Integer::compareTo);
		integers.sort(Comparator.comparing(Integer::intValue));
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章