Java中,List集合對象,預設有一個排序方法sort(Comparator<? super E> c),如果傳遞null,那是對簡單類型的排序,如果是對象類型,并且是需要按照對象類型的某一個屬性字段排序,就需要我們傳入排序的規則。
show me the code:
package com.xxx.huali.hualitest.sort;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListSort {
public static void main(String[] args) {
List<Person> list = new ArrayList<Person>();
list.add(new Person(1,"jack",18));
list.add(new Person(2,"paul",28));
list.add(new Person(3,"zion",20));
list.add(new Person(4,"jone",30));
list.forEach(System.out::println);
//利用Collections.sort方法按照年齡排序,預設升序
Collections.sort(list, (a,b)->{
return a.getAge() - b.getAge();
});
System.out.println("================================");
list.forEach(System.out::println);
//直接使用List集合sort方法按照姓名排序,預設字母升序
list.sort((a,b)->a.getName().compareTo(b.getName()));
System.out.println("================================");
list.forEach(System.out::println);
}
}
class Person{
private int id ;
private String name ;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
public Person() {
}
public Person(int id,String name,int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
示例中,定義了Person對象,分别按照年齡和姓名排序,運作程式,列印結果如下:
Person [id=1, name=jack, age=18]
Person [id=2, name=paul, age=28]
Person [id=3, name=zion, age=20]
Person [id=4, name=jone, age=30]
================================
Person [id=1, name=jack, age=18]
Person [id=3, name=zion, age=20]
Person [id=2, name=paul, age=28]
Person [id=4, name=jone, age=30]
================================
Person [id=1, name=jack, age=18]
Person [id=4, name=jone, age=30]
Person [id=2, name=paul, age=28]
Person [id=3, name=zion, age=20]
排序思路很簡單,就是利用List集合自帶的sort函數,傳入相應的比較函數。
有意思的是,Set集合,是一個不重複的集合,但是它就沒有sort排序方法。
上面的排序算法,我們傳入了排序函數,是使用的lambda表達式的形式,這個是在jdk8以後的版本中才能使用,傳統的做法這裡其實是需要傳入一個匿名内部類Comparator。
list.sort(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getId() - o2.getId();
}
});
另外,數組對象排序,可以使用Arrays.sort()方法,這個方法的對象不能是集合,隻能是數組。
package com.xxx.huali.hualitest.sort;
import java.util.Arrays;
public class ArraySort {
public static void main(String[] args) {
Employee[] emps = new Employee[] {new Employee(1, "jack", 5000),
new Employee(2,"ivan",2888),
new Employee(4, "lisa", 3000),
new Employee(3, "lucy", 9999)};
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
}
Arrays.sort(emps);
}
}
class Employee{
private int id;
private String name;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int id,String name,double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
}
運作代碼,報錯:
Exception in thread "main" java.lang.ClassCastException: com.xxx.huali.hualitest.sort.Employee cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
at java.util.Arrays.sort(Arrays.java:1246)
at com.xxx.huali.hualitest.sort.ArraySort.main(ArraySort.java:12)
根據提示,Employee對象不能轉為Comparable類型。修改代碼,實作Comparable接口,并覆寫方法。
package com.xxx.huali.hualitest.sort;
import java.util.Arrays;
public class ArraySort {
public static void main(String[] args) {
Employee[] emps = new Employee[] {new Employee(1, "jack", 5000),
new Employee(2,"ivan",2888),
new Employee(4, "lisa", 3000),
new Employee(3, "lucy", 9999)};
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
}
Arrays.sort(emps);
System.out.println("=========================================");
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
}
}
}
class Employee implements Comparable<Employee>{
private int id;
private String name;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int id,String name,double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public int compareTo(Employee o) {
return (int)(this.salary - o.getSalary());
}
}
運作代碼,列印結果如下:
Employee [id=1, name=jack, salary=5000.0]
Employee [id=2, name=ivan, salary=2888.0]
Employee [id=4, name=lisa, salary=3000.0]
Employee [id=3, name=lucy, salary=9999.0]
=========================================
Employee [id=2, name=ivan, salary=2888.0]
Employee [id=4, name=lisa, salary=3000.0]
Employee [id=1, name=jack, salary=5000.0]
Employee [id=3, name=lucy, salary=9999.0]
從上面的這個數組集合排序的例子中,我們可以得出一個結論,我們如果要讓Arrays.sort()方法發揮作用,需要讓對象實作Comparable接口,那麼實作了Comparable接口的對象,是否在List.sort()方法中,可以預設排序呢,答案是肯定的。
package com.xxx.huali.hualitest.sort;
import java.util.Arrays;
import java.util.List;
public class ArraySort {
public static void main(String[] args) {
Employee[] emps = new Employee[] {new Employee(1, "jack", 5000),
new Employee(2,"ivan",2888),
new Employee(4, "lisa", 3000),
new Employee(3, "lucy", 9999)};
/*
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
}
Arrays.sort(emps);
System.out.println("=========================================");
for (int i = 0; i < emps.length; i++) {
System.out.println(emps[i]);
}*/
List<Employee> list = Arrays.asList(emps);
list.forEach(System.out::println);
System.out.println("=========================================");
list.sort(null);
list.forEach(System.out::println);
}
}
class Employee implements Comparable<Employee>{
private int id;
private String name;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + "]";
}
public Employee() {
// TODO Auto-generated constructor stub
}
public Employee(int id,String name,double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public int compareTo(Employee o) {
return (int)(this.salary - o.getSalary());
}
}
排序結果:
Employee [id=1, name=jack, salary=5000.0]
Employee [id=2, name=ivan, salary=2888.0]
Employee [id=4, name=lisa, salary=3000.0]
Employee [id=3, name=lucy, salary=9999.0]
=========================================
Employee [id=2, name=ivan, salary=2888.0]
Employee [id=4, name=lisa, salary=3000.0]
Employee [id=1, name=jack, salary=5000.0]
Employee [id=3, name=lucy, salary=9999.0]
結果與上面通過Arrays.sort()對數組對象排序結果是一樣的。
通過前面的介紹,我們知道,對象類型排序,需要實作排序函數,也就是指定排序規則,他們都需要實作Comparable接口或者Comparator接口。
那麼,Comparable vs Comparator:
1、Comprable接口一旦實作,隻能提供一種排序規則,而Comparator可以以匿名内部類的形式提供多種排序方法。
2、使用Comparable接口,需要實作它,而使用Comparator接口,我們無需對原始類作改動,在類中添加額外代碼。
3、Comparable接口是在java.lang包中,而Comparator接口在java.util包中。
4、 Comparable接口已經侵入類中,是以類預設有了排序規則,是以我們在使用排序算法的時候,不需要傳入排序函數,自動使用預設排序compareTo()函數,而使用Comparator接口,我們需要在排序的地方提供compare()函數。
本文編寫過程中參照了一些其他資料:
Comparable and Comparator in Java Example - JournalDev