天天看點

Java中List對象集合按照對象某一屬性字段排序

    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