* 在使用Collection的sort排序的集合元素都必須是Comparable接口的實現類,該接口表示子類是可以比較的。 * 同時實現接口必須重寫抽象方法。 * - int compareTo(T t); * 該方法用於使當前對象與給定對象進行比較。 * 返回值為一個int值,該值表示大小關系,它不關注具體的取值是多少,而關注的是取值范圍。 * 當返回值>0時:當前對象比參數對象大(T是傳入的參數,this表示當前對象) * 當返回值<0時:當前對象比參數對象小(T是傳入的參數,this表示當前對象) * 當返回值=0時:當前對象等於參數對象(T是傳入的參數,this表示當前對象)
package example.demo03; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * @author yuanchaoyong */
public class ComparatorTest { public static void main(String[] args) { // 測試案例1
testInteger(); // 測試案例2
testString(); } /** * List<Integer> 排序測試 * Integer 默認實現了Comparable接口 * Collections.sort默認是升序排序(自然排序) */
public static void testInteger(){ List<Integer> integers = Arrays.asList(12,7,15,4); Collections.sort(integers); System.out.println(integers); } /** * List<String> 排序測試 * String 默認實現了Comparable接口 * Collections.sort默認是升序排序(自然排序) */
public static void testString(){ List<String> strings = Arrays.asList("aaa","ccc","bbb","rrr"); Collections.sort(strings); System.out.println(strings); } }
輸出結果

package example.demo03; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * @author yuanchaoyong */
public class ComparatorTest02 { public static void main(String[] args) { List<User> users = Arrays.asList(new User("王五",50),new User("張三",30),new User("李四",40)); Collections.sort(users); System.out.println(users); } } /** * 用戶對象 * name * age */
class User implements Comparable<User>{ String name; Integer age; User(String n, Integer a) { name = n; age = a; } @Override public int compareTo(User u) { return this.age - u.age ; } @Override public String toString() { return String.format("{name=%s, age=%d}", name, age); } }

通過以上案例知道,Comparable的確實現了我們想要的排序結果。但是使用Collections的sort(List<T> list) 方法排序集合時,集合元素必須實現Comparable接口並且定義比較規則。這個時候就開始出現一些問題。比如我們同一個工程使用了User對象,單個場景使用age進行排序,但是另一種情況下使用name排序,這個時候就出現了沖突。並且集合元素需要去實現Comparable接口,這對於我們的代碼會有一些"侵入性",也不利於我們后續的代碼擴展。
所以一般不建議使用,推薦使用Collections的sort(List<T> list, Comparator<? super T> c)的重載方法。
Collections的sort(List<T> list, Comparator<? super T> c)
* 重載的sort方法要求傳入一個外部的比較器。 * 該方法不再要求集合元素必須實現Comparable接口。 * 並且也不再使用集合元素自身的比較規則排序了,而是根據給定的這個額外的比較器的比較規則,對集合元素進行排序。 * 實際開發中也推薦使用這種方式排序集合元素,若集合元素是自定義的,創建比較器時也推薦使用匿名內部類的形式。
package example.demo03; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * @author yuanchaoyong */
public class ComparatorTest03 { public static void main(String[] args) { List<Student> students = Arrays.asList(new Student("張三",30),new Student("李四",40),new Student("王五",50)); // 使用匿名內部類進行排序
Collections.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 自定義排序規則
return o1.age- o2.age; } }); System.out.println(students); } } class Student { String name; Integer age; Student(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return String.format("{name=%s, age=%d}", name, age); } }
結果

package example.demo03; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * @author yuanchaoyong */
public class ComparatorTest03 { public static void main(String[] args) { //test01();
test02(); } /** * 使用List自帶的排序方法 */
private static void test02() { List<Student> students = Arrays.asList(new Student("張三",30),new Student("李四",40),new Student("王五",50)); students.sort(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.age- o2.age; } }); System.out.println(students); } /** * Collections.sort方法測試 */
private static void test01() { List<Student> students = Arrays.asList(new Student("張三",30),new Student("李四",40),new Student("王五",50)); // 使用匿名內部類進行排序
Collections.sort(students, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 自定義排序規則
return o1.age- o2.age; } }); System.out.println(students); } } class Student { String name; Integer age; Student(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return String.format("{name=%s, age=%d}", name, age); } }

JDK8之lambda簡化寫法
Comparator接口是一個函數式接口,所以我們可以使用更優秀的寫法,簡化代碼。
函數式接口就是只定義一個抽象方法的接口。
JDK1.8開始支持默認方法,即便這個接口擁有很多默認方法,只要接口只有一個抽象方法,那么這個接口就是函數式接口。
package example.demo03; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; /** * @author yuanchaoyong */
public class ComparatorTest04 { public static void main(String[] args) { test02(); } /** * lambda寫法測試 */
private static void test02() { List<Teacher> teachers = Arrays.asList(new Teacher("張三", 30), new Teacher("李四", 40), new Teacher("王五", 50)); // 多種寫法,以下只是作為參考 // 寫法1 // teachers.stream().sorted((o1,o2)-> o1.age- o2.age).collect(Collectors.toList()); // 寫法2 //Collections.sort(teachers,(o1,o2)-> o1.getAge()- o2.getAge()); // 寫法3
List<Teacher> teacherList = teachers.stream(). sorted((Comparator.comparingInt(Teacher::getAge))) .collect(Collectors.toList()); System.out.println(teachers); } } class Teacher { String name; Integer age; Teacher(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } @Override public String toString() { return String.format("{name=%s, age=%d}", name, age); } }
List<類> list; 代表某集合 //返回 對象集合以類屬性一升序排序
list.stream().sorted(Comparator.comparing(類::屬性一)); //返回 對象集合以類屬性一降序排序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed());//先以屬性一升序,結果進行屬性一降序
list.stream().sorted(Comparator.comparing(類::屬性一,Comparator.reverseOrder()));//以屬性一降序 //返回 對象集合以類屬性一升序 屬性二升序
list.stream().sorted(Comparator.comparing(類::屬性一).thenComparing(類::屬性二)); //返回 對象集合以類屬性一降序 屬性二升序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed().thenComparing(類::屬性二));//先以屬性一升序,升序結果進行屬性一降序,再進行屬性二升序
list.stream().sorted(Comparator.comparing(類::屬性一,Comparator.reverseOrder()).thenComparing(類::屬性二));//先以屬性一降序,再進行屬性二升序 //返回 對象集合以類屬性一降序 屬性二降序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed().thenComparing(類::屬性二,Comparator.reverseOrder()));//先以屬性一升序,升序結果進行屬性一降序,再進行屬性二降序
list.stream().sorted(Comparator.comparing(類::屬性一,Comparator.reverseOrder()).thenComparing(類::屬性二,Comparator.reverseOrder()));//先以屬性一降序,再進行屬性二降序 //返回 對象集合以類屬性一升序 屬性二降序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed().thenComparing(類::屬性二).reversed());//先以屬性一升序,升序結果進行屬性一降序,再進行屬性二升序,結果進行屬性一降序屬性二降序
list.stream().sorted(Comparator.comparing(類::屬性一).thenComparing(類::屬性二,Comparator.reverseOrder()));//先以屬性一升序,再進行屬性二降序 //空/Null數據排序
list.stream().sorted(Comparator.comparing(類::屬性一).thenComparing(item -> item.屬性二, Comparator.nullsLast(Date::compareTo))).collect(Collectors.toList()); //空/Null數據分組
Map<String, List<類>> map = list.stream().collect(Collectors.groupingBy(item -> { if (item.屬性一 == null || item.屬性一.equals("")) { return ""; } return DateFormat.getDateInstance().format(item.屬性一); }))

