使用 Comparable接口 对自定义对象进行自然排序
Comparable
接口支持它实现的类的自然排序。
它使类与它的其他实例具有可比性。
实现 Comparable
接口的类必须覆盖 compareTo() 方法,在该方法中它可以指定同一类的两个实例之间的比较逻辑。
实现此接口的对象列表(和数组)可以通过 Collections.sort()
和 Arrays.sort()
自动排序。
实现此接口的对象在放入排序映射(作为键)或者排序集(作为元素)时将自动排序。
强烈建议(虽然不是必需的)自然顺序与 equals()
方法一致。
几乎所有实现 Comparable
的 Java 核心类都具有与 equals()
一致的自然顺序。
ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1l, "Alex", LocalDate.of(2018, Month.APRIL, 21))); list.add(new Employee(4l, "Brian", LocalDate.of(2018, Month.APRIL, 22))); list.add(new Employee(3l, "Piyush", LocalDate.of(2018, Month.APRIL, 25))); list.add(new Employee(5l, "Charles", LocalDate.of(2018, Month.APRIL, 23))); list.add(new Employee(2l, "Pawan", LocalDate.of(2018, Month.APRIL, 24))); Collections.sort(list); System.out.println(list);
程序输出。
[Employee [id=1, name=Alex, dob=2018-04-21], ] Employee [id=2, name=Pawan, dob=2018-04-24], Employee [id=3, name=Piyush, dob=2018-04-25], Employee [id=4, name=Brian, dob=2018-04-22], Employee [id=5, name=Charles, dob=2018-04-23]]
Java排序自定义对象的多个字段
使用链中的多个比较器对不同字段上的对象集合进行排序(groupby sort)。
这种比较器链可以使用 Comparator.comparing() 和 Comparator.thenComparing() 方法创建。
例如,我们按姓名对员工列表进行排序,然后再按年龄排序。
ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1l, "Alex", LocalDate.of(2018, Month.APRIL, 21))); list.add(new Employee(4l, "Brian", LocalDate.of(2018, Month.APRIL, 01))); list.add(new Employee(3l, "Alex", LocalDate.of(2018, Month.APRIL, 25))); list.add(new Employee(5l, "Charles", LocalDate.of(2018, Month.APRIL, 23))); list.add(new Employee(2l, "Alex", LocalDate.of(2018, Month.APRIL, 30))); Collections.sort(list, Comparator .comparing(Employee::getName) .thenComparing(Employee::getDob)); System.out.println(list);
程序输出。
[Employee [id=1, name=Alex, dob=2018-04-21], Employee [id=3, name=Alex, dob=2018-04-25], Employee [id=2, name=Alex, dob=2018-04-30], Employee [id=4, name=Brian, dob=2018-04-01], Employee [id=5, name=Charles, dob=2018-04-23]]
Java 使用比较器(Comparator) 对自定义对象 排序
很多时候,我们面临的情况是,由于遗留代码问题,我们不寻求自然排序或者源代码不可用以进行编辑。
在这种情况下,我们可以借助 Comparator 接口。
Comparator
不需要修改类的源代码。
我们可以在单独的类中创建比较逻辑,实现 Comparator
接口并覆盖它的 compare()
方法。
然后将此比较器与自定义对象列表一起传递给 sort() 方法。
例如,在 Comparator
下面按员工的 name
对列表进行排序。
import java.util.Comparator; public class NameSorter implements Comparator<Employee> { @Override public int compare(Employee e1, Employee e2) { return e1.getName().compareToIgnoreCase( e2.getName() ); } }
使用“比较器”接口实现对列表进行排序的 Java 程序。
请注意在 sort()
方法中使用 NameSorter
作为第二个参数。
ArrayList<Employee> list = new ArrayList<>(); list.add(new Employee(1l, "Alex", LocalDate.of(2018, Month.APRIL, 21))); list.add(new Employee(4l, "Brian", LocalDate.of(2018, Month.APRIL, 22))); list.add(new Employee(3l, "Piyush", LocalDate.of(2018, Month.APRIL, 25))); list.add(new Employee(5l, "Charles", LocalDate.of(2018, Month.APRIL, 23))); list.add(new Employee(2l, "Pawan", LocalDate.of(2018, Month.APRIL, 24))); Collections.sort(list, new NameSorter()); System.out.println(list);
程序输出。
[Employee [id=1, name=Alex, dob=2018-04-21], Employee [id=4, name=Brian, dob=2018-04-22], Employee [id=5, name=Charles, dob=2018-04-23], Employee [id=2, name=Pawan, dob=2018-04-24], Employee [id=3, name=Piyush, dob=2018-04-25]]
自定义对象是用户定义的类,用于存储域数据,例如Employee
、Department
、Account
等。
为了对自定义对象列表进行排序,我们有两种流行的方法,例如:Comparable 和 Comparator 接口。
在给定的示例中,我们将对“Employee”对象的集合进行排序。
import java.time.LocalDate; public class Employee implements Comparable<Employee> { private Long id; private String name; private LocalDate dob; public Employee(Long id, String name, LocalDate dob) { super(); this.id = id; this.name = name; this.dob = dob; } @Override public int compareTo(Employee o) { return this.getId().compareTo(o.getId()); } //Getters and Setters shall be added here @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", dob=" + dob + "]"; } }
使用 Java 8 Lambda 排序自定义对象
Java 8 Lambda 表达式有助于即时编写“Comparator”实现。
我们不需要创建单独的类来提供一次性比较逻辑。
Comparator<Employee> nameSorter = (a, b) -> a.getName().compareToIgnoreCase(b.getName()); Collections.sort(list, nameSorter);