Java中,List集合对象,默认有一个排序方法sort(Comparator 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 list = new ArrayList();
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() {
@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{
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 list = Arrays.asList(emps);
list.forEach(System.out::println);
System.out.println("=========================================");
list.sort(null);
list.forEach(System.out::println);
}
}
class Employee implements Comparable{
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