Collections.sort對List排序的兩種方法
一、Collections.sort的簡單使用
說到List的排序,第一反應當然是使用Collections.sort,方便簡單。下面實現一下~~
private void sortStrings() { List<String> list = new ArrayList<String>(); list.add("ccc"); list.add("aaa"); list.add("bbb"); //排序 Collections.sort(list); //輸出 Log.d(TAG, "-----------對字串排序-----------"); for(String item : list) { Log.d(TAG, item.toString()); } }
02-03 10:32:25.821: D/wxx(4732): -----------對字串排序-----------
02-03 10:32:25.821: D/wxx(4732): aaa
02-03 10:32:25.821: D/wxx(4732): bbb
02-03 10:32:25.821: D/wxx(4732): ccc
可見,實現了對List<String>的排序,非常簡單。
二、問題提出
但在我們的專案中列表List的元素型別經常是自定義的,下面自定義了一個實體類Person:
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } }
然後,想對Person的列表List<Person>進行排序,首先想到的也是通過Collections.sort進行排序:
private void sortPerson() { Person p1 = new Person("ccc", 20); Person p2 = new Person("aaa", 18); Person p3 = new Person("bbb", 16); List<Person> list = new ArrayList<Person>(); list.add(p1); list.add(p2); list.add(p3); //排序 Collections.sort(list); }
發現,程式碼直接報錯了:
Bound mismatch: The generic method sort(List<T>) of type Collections is not applicable for the arguments (List<Person>). The inferred type Person is not a valid substitute for the bounded
parameter <T extends Comparable<? super T>>
從上面可知,Person不是一個有效的引數型別,而應該extends Comparable。為什麼?
原來,要排序嘛當然要有排序的規則,比如按身高從高到低,按年齡從小到大,等等,也就是要有比較。而String這個物件已經幫我們實現了Comparable介面,所以String型別自己就是可以比較的。而我們的Person如果想要排序,也必須能夠按某種規則進行比較,也就是要實現一個比較器。我們可以通過實現Comparable或Comparator介面實現比較器 。
三、Comparable實現排序
Comparable實現比較器,是定義在Person類的內部的,所以實體類Person需要implements Comparable<Person>,然後重寫compareTo方法,在此方法裡實現比較規則,規則就是先比較名字,如果名字不一樣則返回比較結果,如果名字一樣,再比較年齡,返回比較結果:
public class Person implements Comparable<Person> {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int compareTo(Person another) {
int i = name.compareTo(another.name); //比較名字字串
if (i == 0) { //如果名字一樣,則繼續比較年齡
return age - another.age;
} else { //首先比較名字,名字不一樣,則返回比較結果
return i;
}
}
}
後面就是對List<Person>進行排序並輸出:
private void sortByComparable() {
Person p1 = new Person("bbb", 20);
Person p2 = new Person("aaa", 18);
Person p3 = new Person("bbb", 16);
List<Person> list = new ArrayList<Person>();
list.add(p1);
list.add(p2);
list.add(p3);
//排序
Collections.sort(list);
//輸出
Log.d(TAG, "-----------使用Comparable實現的排序-----------");
for(Person item : list) {
Log.d(TAG, "name = "+item.name+", age = "+item.age);
}
}
檢查輸出結果是否正確:
02-03 12:05:31.356: D/wxx(9936): -----------使用Comparable實現的排序-----------
02-03 12:05:31.356: D/wxx(9936): name = aaa, age = 18
02-03 12:05:31.356: D/wxx(9936): name = bbb, age = 16
02-03 12:05:31.356: D/wxx(9936): name = bbb, age = 20
四、Comparator實現排序
Comparator實現比較器,是定義在Person類的外部的,因此實體類Person不需要做任何變化,如下:
public class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
我們的比較器MyComparator的實現,主要是覆蓋compare方法,在這個方法內實現比較的規則,具體程式碼:
public class MyComparator implements Comparator<Person> {
public int compare(Person one, Person two) {
int i = one.name.compareTo(two.name); //比較名字字串
if (i == 0) { //如果名字一樣,則繼續比較年齡
return one.age - two.age;
} else { //首先比較名字,名字不一樣,則返回比較結果
return i;
}
}
}
上面的排序規則是:先比較name值進行排序,如果name值一樣 ,再比較age值排序。
最後,當然是用我們的比較器對List<Person>進行排序: private void sortByComparator() {
Person p1 = new Person("bbb", 20);
Person p2 = new Person("aaa", 18);
Person p3 = new Person("bbb", 16);
List<Person> list = new ArrayList<Person>();
list.add(p1);
list.add(p2);
list.add(p3);
//排序
Collections.sort(list, new MyComparator());
//輸出
Log.d(TAG, "-----------使用Comparator實現的排序-----------");
for(Person item : list) {
Log.d(TAG, "name = "+item.name+", age = "+item.age);
}
}
檢視排序後的輸出結果是否正確:
02-03 11:51:34.996: D/wxx(1355): -----------使用Comparator實現的排序-----------
02-03 11:51:34.996: D/wxx(1355): name = aaa, age = 18
02-03 11:51:35.001: D/wxx(1355): name = bbb, age = 16
02-03 11:51:35.001: D/wxx(1355): name = bbb, age = 20
五、Comparable 與Comparator區別
上面已經分別實現了Comparable 與Comparator對List進行排序,他們有相似的地方,也有不同的地方:
1)Comparable 與Comparator都是java的介面,用來對自定義的實體物件進行比較;
2)Comparable 是定義在實體類內部的,所以實體類物件本身就有比較大小的可能。但如果想換一種比較規則,如先按年齡後按名字排序,那麼就必須修改實體類Person本身;
3)Comparator是在實體類外部實現比較器的,所以對List排序時必須同時傳入資料和比較器,如Collections.sort(list, new MyComparator());如果想換一種比較規則,則僅需要修改比較器MyComparator,而實體類Person則不需要改變;所以建議使用這種方法;
4)Comparable實現程式碼相對簡單,Comparator實現程式碼相對複雜一點,但還是建議使用Comparator方法。