記得初學Java的時候,若要對List進行排序,可以使用Collections的靜態方法sort(),若List裡面裝的是基本型態(Primitive Type)的數值以及字串(String)就可以直接由小到大排序;不過若是想要由大到小排序的時候,就會看到下面這樣的寫法:
List<Integer> list = Arrays.asList(2, 1, 3);
Collections.sort(list, (i1, i2) -> -i1.compareTo(i2));
我那時就有2個疑惑:這個compareTo()是哪來的?怎麼印象中還有個方法是compare()?而又為什麼只要在原本的compareTo結果上加一個負號,就會是變成相反的排序呢?
要解除這2個疑惑,就需要了解到Comparable介面以及Comparator介面了。
首先為什麼我們可以直接針對裝有基本型態或者字串的List來進行Collections的sort方法呢?這是因為這些類別的比較規則Java都幫我們寫好了~
如果查看Integer, Float, String等類別,會發現他們都實作(implements)了Comparable介面,而Comparable介面就只有一個compareTo方法,會回傳一個int值:
obj1.compareTo(obj2) 大於0:obj1排序大於obj2,會被排到後面
obj1.compareTo(obj2) 等於0:obj1排序與obj2相等
obj1.compareTo(obj2) 小於0:obj1排序小於obj2,會被排到前面
所以Collections.sort(List)的方法實作就是叫用每個元素的compareTo來進行比大小,所以如果我們的List裡頭放的是我們自己定義的類別物件,那我們就必須要實作Comparable介面並覆寫(Override) compareTo 方法。
但有辦法每個物件都去實作Comparable嗎?又或者當我們想要幫基本型態或字串等類別自己定義其他比較規則時,就沒轍了嗎?(沒轍因為基本型態與String都被冠上了final)
這時Comparator就登場了~Comparator介面中的compare()方法就相當於Comparable的compareTo(),我們比對觀察一下:
Comparable:int compareTo(T o)
Comparator:int compare(T o1, T o2)
這兩者的差別在於參數的數量以及由什麼物件來呼叫。compareTo是直接被實作在有實施Comparable的類別中,所以是由該物件實例來直接呼叫,引數只要放入另一個要拿來被比較的物件就好了;Comparator則是類似一個額外工具的概念,並不是直接定義在物件的類別之中,所以要使用時需要傳入2個要進行比較的物件。回傳值的定義是一樣的。
這樣的做法就讓我們可以自由定義compare所需要的排序比較規則了!
而我們在Java API Collections的sort()方法中可以看到有兩個重載(overload)版本:
sort(List list)
sort(List list, Comparator<? super T> c)
我們就可以把自己定義的Comparator利用重載版本的sort來使用囉。
小結: