1. 概述
在这个教程中,我们将讨论如何根据日期对列表中的对象进行排序。大多数排序技巧或示例都让用户按字母顺序对列表进行排序,但本文将探讨如何使用List
(/java-collections)中的Date
对象进行排序。
我们将利用Java的Comparator
类来自定义排序列表的值。
2. 准备工作
让我们看看在本篇文章中将使用的Employee
实体:
public class Employee implements Comparable<Employee> {
private String name;
private Date joiningDate;
public Employee(String name, Date joiningDate) {
// ...
}
// standard getters and setters
}
我们可以注意到Employee
类实现了Comparable
接口。这个接口允许我们定义一个策略,用于比较同类型的对象之间的比较。这被用来按照自然顺序或由compareTo()
方法定义的顺序对对象进行排序。
3. 使用Comparable
进行排序
在Java中,自然排序指的是如何在数组或集合中对基本类型或对象进行排序。java.util.Arrays
和java.util.Collections
包中的sort()
方法应该是一致的,并反映相等性的语义。
我们将使用此方法来比较当前对象和传入的对象:
public class Employee implements Comparable<Employee> {
// ...
@Override
public boolean equals(Object obj) {
return ((Employee) obj).getName().equals(getName());
}
@Override
public int compareTo(Employee employee) {
return getJoiningDate().compareTo(employee.getJoiningDate());
}
}
这个compareTo()
方法将比较当前对象与传递给它的对象。在上述例子中,我们比较当前员工的入职日期与传入的Employee
对象。
3.1. 以升序排序
通常情况下,compareTo()
方法描述了对象之间自然排序的比较逻辑。在这里,我们比较员工的入职日期字段与其他同类型的对象。如果两个员工的入职日期相同,它们将返回0:
@Test
public void givenEmpList_SortEmpList_thenSortedListinNaturalOrder() {
Collections.sort(employees);
assertEquals(employees, employeesSortedByDateAsc);
}
现在,Collections.sort(employees)
会根据joiningDate
而不是主键或名称对员工列表进行排序。我们可以看到,列表已根据员工的joiningDate
进行排序,这成为了Employee
类的自然顺序:
[(Pearl,Tue Apr 27 23:30:47 IST 2021),
(Earl,Sun Feb 27 23:30:47 IST 2022),
(Steve,Sun Apr 17 23:30:47 IST 2022),
(John,Wed Apr 27 23:30:47 IST 2022)]
3.2. 以降序排序
Collections.reverseOrder()
方法按自然顺序的相反顺序对对象进行排序。它返回一个比较器,可以执行逆序排序。当对象在比较时返回null
时,它将抛出NullPointerException
:
@Test
public void givenEmpList_SortEmpList_thenSortedListinDescOrder() {
Collections.sort(employees, Collections.reverseOrder());
assertEquals(employees, employeesSortedByDateDesc);
}
4. 使用Comparator
进行排序
4.1. 以升序排序
现在,让我们使用Comparator
接口实现来对员工列表进行排序。这里,我们将传递一个匿名内部类作为参数,即时传递给Collections.sort()
API:
@Test
public void givenEmpList_SortEmpList_thenCheckSortedList() {
Collections.sort(employees, new Comparator<Employee>() {
public int compare(Employee o1, Employee o2) {
return o1.getJoiningDate().compareTo(o2.getJoiningDate());
}
});
assertEquals(employees, employeesSortedByDateAsc);
}
我们也可以将此语法替换为Java 8的Lambda语法,使代码更简洁,如下所示:
@Test
public void givenEmpList_SortEmpList_thenCheckSortedListAscLambda() {
Collections.sort(employees, Comparator.comparing(Employee::getJoiningDate));
assertEquals(employees, employeesSortedByDateAsc);
}
compare(arg1, arg2)
方法接受两个泛型类型的参数并返回一个整数。由于它与类定义分离,我们可以根据不同的变量和实体定义自定义比较。当需要为比较对象定义不同的自定义排序时,这非常有用。
4.2. 以降序排序
我们可以通过反转员工对象的比较来按降序对给定的Employee
列表进行排序,即比较Employee2
与Employee1
。这将反转比较,从而返回降序结果:
@Test
public void givenEmpList_SortEmpList_thenCheckSortedListDescV1() {
Collections.sort(employees, new Comparator<Employee>() {
public int compare(Employee emp1, Employee emp2) {
return emp2.getJoiningDate().compareTo(emp1.getJoiningDate());
}
});
assertEquals(employees, employeesSortedByDateDesc);
}
我们还可以使用Java 8的Lambda表达式将上述方法转换为更简洁的形式。这将执行与上述函数相同的功能,只是代码行数比上述代码少。然而,这也使得代码不太易读。在使用Comparator
时,我们在Collections.sort()
API上即时传递了一个匿名内部类:
@Test
public void givenEmpList_SortEmpList_thenCheckSortedListDescLambda() {
Collections.sort(employees, (emp1, emp2) -> emp2.getJoiningDate().compareTo(emp1.getJoiningDate()));
assertEquals(employees, employeesSortedByDateDesc);
}
5. 总结
在这篇文章中,我们探讨了如何在Java集合中按日期对象的升序和降序对列表进行排序。
我们也简要介绍了Java 8的Lambda特性,这些特性在排序中很有用,可以帮助我们使代码更简洁。
如往常一样,本文中使用的完整代码示例可以在GitHub上找到。