List在Java中做sort : Collection.sort() === ## Discription 將資料收集進List後,常常會使用到sort,而此動作不需要自己去實作,在java.util.Collections提供sort的方法,Ex: ``Ex 1:`` ```java= import java.util.*; public class Main { public static void main(String[] args) { List<Integer> count = new ArrayList<>(); count.add(500); count.add(50); count.add(5000); count.add(5); Collections.sort(count); for(int k: count) System.out.println(k); //Output: //5 //50 //500 //5000 } } ``` 會是以升序排序 --- 但如果List中存放的是自定義物件呢? ``Ex2`` ```java= import java.util.*; public class Main { public static void main(String[] args) { List P = Arrays.asList( new Person("Justin", 1000,false), new Person("Monica", 500,true), new Person("Irene", 200,false) ); Collections.sort(P); } } class Person { private String name ; private int money; private boolean marry; public Person(String name ,int money,boolean marry) { this.name = name; this.money = money; this.marry = marry; } } ``` 執行結果會跳出:==ClassCastException== Why?? 因為==Collection並不知道要sort自定義物件的哪一個property==(i.e **name?** or **monry?** or **marry?**),也沒加以說明 --- ## Comparable Collections的sort()方法要求被排序的物件,必須實作java.lang.Comparable介面,這個介面有個compareTo()方法必須傳回大於0、等於0或小於0的數, Collections的sort()方法在取得a物件跟b物件進行比較時,會先a物件扮演(Cast)為Comparable(也因此若物件沒實作Comparable,將會拋出ClassCastException,若使用了泛型宣告,編譯器會檢查出型態不符),然後呼叫a.compareTo(b),如果a物件==順序上小於==b物件,必須==傳回小於0==,若==順序上相等==則==傳回0==,若==順序上a大於b==則==傳回大於0==的值。 **所以只要在物件上實作Comparable的compareTo(比較方法):** ``Ex3`` ```java= import java.util.*; public class Main { public static void main(String[] args) { List<Person> P = new ArrayList<>(); P.add( new Person("Justin", 1000,false)); P.add(new Person("Monica", 500,true)); P.add( new Person("Irene", 200,false)); Collections.sort(P); for(Person s :P) System.out.println(s.money); //Output //200 //500 //1000 } } class Person implements Comparable<Person> { private String name ; public int money; private boolean marry; public Person(String name ,int money,boolean marry) { this.name = name; this.money = money; this.marry = marry; } @Override public int compareTo(Person other) { /* if(this.money > other.money) return 1; if(this.money < other.money) return -1; return 0; */ //simplify return this.money - other.money; } } ``` --- ## Problem **若在實際情況中無法修改物件或無法取的原始碼**,而==無法實作Comparable==呢?(e.g String為final物件無法被繼承) Collections的sort()方法有另一個重載版本,可接受java.util.Comparator介面的實作物件,如果你使用這個版本,排序方式將根據Comparator的==compare()定義==來決定。 ``Ex4`` ```java= import java.util.*; public class Main { public static void main(String[] args) { List<Person> P = new ArrayList<>(); P.add( new Person("Justin", 1000,false)); P.add(new Person("Monica", 500,true)); P.add( new Person("Irene", 200,false)); // Collections.sort(P,(a,b) -> (a.money - b.money)); Collections.sort(P,new Comparator<Person>(){ @Override public int compare(Person a,Person b) { return a.money - b.money; } }); for(Person s :P) System.out.println(s.money); //Output //200 //500 //1000 } } class Person { private String name ; public int money; private boolean marry; public Person(String name ,int money,boolean marry) { this.name = name; this.money = money; this.marry = marry; } } ``` 或是使用lambda表示式簡化: ``Ex5`` ```java= import java.util.*; public class Main { public static void main(String[] args) { List<Person> P = new ArrayList<>(); P.add( new Person("Justin", 1000,false)); P.add(new Person("Monica", 500,true)); P.add( new Person("Irene", 200,false)); Collections.sort(P,(a,b) -> (a.money - b.money)); for(Person s :P) System.out.println(s.money); //Output //200 //500 //1000 } } class Person { private String name ; public int money; private boolean marry; public Person(String name ,int money,boolean marry) { this.name = name; this.money = money; this.marry = marry; } } ``` `` Collections.sort(P,(a,b) -> (a.money - b.money)); `` 第二個Input Argument 已知為Compartor型態因而不必再給,input argument,(a,b)自行判斷其形態也省略,輸出為a.money - b.money ## Conclusion 當要對List進行sort,若為一般型態(e.g Integer,String...)則可以直接使用,但若型態為自定義class,則要實作comparator來給出誰跟誰比的定義. ## Reference https://openhome.cc/Gossip/Java/ComparableComparator.html ###### tags: `java` `Sort`