我們知道Set與List的最大區別就是Set中的元素不可以重復(這個重復指的equals方法的返回值相等),其他方面則沒有太大的區別了,在Set的實現類中有一個比較常用的類需要了解一下:TreeSet,該類實現了類默認排序為升序的Set集合,如果插入一個元素,默認會按照升序排列(當然是根據Comparable接口的compareTo的返回值確定排序位置了),不過,這樣的排序是不是在元素經常變化的場景中也適用呢?我們來看例子:
1 import java.util.SortedSet; 2 import java.util.TreeSet; 3 4 public class Client { 5 public static void main(String[] args) { 6 SortedSet<Person> set = new TreeSet<Person>(); 7 //身高180CM 8 set.add(new Person(180)); 9 //身高175CM 10 set.add(new Person(175)); 11 12 for(Person p:set){ 13 System.out.println("身高:"+p.getHeight()); 14 } 15 } 16 17 static class Person implements Comparable<Person>{ 18 //身高 19 private int height; 20 21 public Person(int _age){ 22 height = _age; 23 } 24 25 26 public int getHeight() { 27 return height; 28 } 29 30 31 public void setHeight(int height) { 32 this.height = height; 33 } 34 35 //按照身高排序 36 public int compareTo(Person o) { 37 return height - o.height; 38 } 39 40 } 41 }
?
程序輸出:
身高:175
身高:180
?
這沒有問題,隨著時間的推移,身高175cm的人長高了10cm,而180cm卻保持不變,那排序的位置應該改變一下吧,看代碼(只需修改main方法):
1 public static void main(String[] args) { 2 SortedSet<Person> set = new TreeSet<Person>(); 3 // 身高180CM 4 set.add(new Person(180)); 5 // 身高175CM 6 set.add(new Person(175)); 7 // 身高最矮的人大變身 8 set.first().setHeight(185); 9 for (Person p : set) { 10 System.out.println("身高:" + p.getHeight()); 11 } 12 }
?
程序輸出:
身高:185
身高:180
很可惜,竟然沒有重新排序,偏離了我們的預期。這正是下面要說明的問題,SortedSet接口(TreeSet實現了該接口)只是定義了在給集合加入元素時將其進行排序,并不能保證元素修改后的排序結果,因此TreeSet使用于不變量的集合數據排序,比如String、Integer等類型,但不適用于可變量的排序,特別是不確定何時元素會發生變化的數據集合。?
原因知道了,那如何解決此類重排序問題呢?有兩種方式:?
(1).Set集合重排序?
重新生成一個Set對象,也就是對原有的Set對象重排序,代碼如下:
1 import java.util.ArrayList; 2 import java.util.SortedSet; 3 import java.util.TreeSet; 4 5 public class Client { 6 public static void main(String[] args) { 7 SortedSet<Person> set = new TreeSet<Person>(); 8 // 身高180CM 9 set.add(new Person(180)); 10 // 身高175CM 11 set.add(new Person(175)); 12 // 身高最矮的人大變身 13 set.first().setHeight(185); 14 //set重排序 15 set = new TreeSet<Person>(new ArrayList<Person>(set));
//set = new TreeSet(set);該構造函數只是原Set的淺拷貝,如果里面有相同的元素,是不會重新排序的 16 for (Person p : set) { 17 System.out.println("身高:" + p.getHeight()); 18 } 19 } 20 21 static class Person implements Comparable<Person> { 22 // 身高 23 private int height; 24 25 public Person(int _age) { 26 height = _age; 27 } 28 29 public int getHeight() { 30 return height; 31 } 32 33 public void setHeight(int height) { 34 this.height = height; 35 } 36 37 // 按照身高排序 38 public int compareTo(Person o) { 39 return height - o.height; 40 } 41 42 } 43 }
?
程序輸出:
身高:180
身高:185
就一句話即可重新排序。可能有讀者會問,使用TreeSet(SortedSet< E > s)這個構造函數不是可以更好地解決問題嗎?不行,該構造函數只是原Set的淺拷貝,如果里面有相同的元素,是不會重新排序的。?
(2).徹底重構掉TreeSet,使用List解決問題?
我們之所以使用TreeSet是希望實現自動排序,即使修改也能自動排序,既然它無法實現,那就用List來代替,然后再使用Collections.sort()方法對List排序.看代碼:
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.List; 4 import java.util.TreeSet; 5 6 public class Client { 7 public static void main(String[] args) { 8 List<Person> list = new ArrayList<Person>(); 9 // 身高180CM 10 list.add(new Person(180)); 11 // 身高175CM 12 list.add(new Person(175)); 13 // 身高最矮的人大變身 14 list.get(1).setHeight(185); 15 16 //排序 17 Collections.sort(list); 18 for (Person p : list) { 19 System.out.println("身高:" + p.getHeight()); 20 } 21 } 22 23 static class Person implements Comparable<Person> { 24 // 身高 25 private int height; 26 27 public Person(int _age) { 28 height = _age; 29 } 30 31 public int getHeight() { 32 return height; 33 } 34 35 public void setHeight(int height) { 36 this.height = height; 37 } 38 39 // 按照身高排序 40 public int compareTo(Person o) { 41 return height - o.height; 42 } 43 44 } 45 }
?
程序輸出:
身高:180
身高:185
?
兩種方法都可以解決我們的困境,到底哪一個是最優的呢?對于不變量的排序,例如直接量(也就是8個基本類型)、String類型等,推薦使用TreeSet,而對于可變量,例如我們自己寫的類,可能會在邏輯處理中改變其排序關鍵值的,則建議使用List自行排序。?
又有問題了,如果需要保證集合中元素的唯一性,又要保證元素值修改后排序正確,那該如何處理呢?List不能保證集合中的元素唯一,它是可以重復的,而Set能保證元素唯一,不重復。如果采用List解決排序問題,就需要自行解決元素重復問題(若要剔除也很簡單,轉變為HashSet,剔除后再轉回來)。若采用TreeSet,則需要解決元素修改后的排序問題,孰是孰非,就需要根據具體的開發場景來決定了。
?