我有一个具有这种结构的对象列表
List<Employee> empList = new ArrayList<>();
empList.add(new Employee(1, "2022-07-07", "15:31"));
empList.add(new Employee(2, "2022-07-07", "12:15"));
empList.add(new Employee(3, "2021-04-05", "20:55"));
empList.add(new Employee(4, "2021-03-05", "17:14"));
是否可以使用流API来查找具有最新日期和时间的对象?在本例中,我将获得第一个对象.
我知道可以这样做,但在这种情况下,我只按日期过滤,我不确定重复的日期是否会造成问题。
Comparator<Employee> employeeComparator =
Comparator.comparing(Employee::getDate);
Employee emp = getEmployeeList().stream()
.max(employeeComparator)
.get();
永远不要使用字符串来表示日期-时间信息。相反,使用java.time
包中的Java 8类,如LocalDateTime
。
这样的假设Employee
重新实现:
public class Employee {
private String name;
private LocalDateTime date;
// constructor, getters, etc.
}
比较器将是:
Comparator<Employee> byDate = Comparator.comparing(Employee::getDate);
它恰好与您所写的相同,并且由于您最初的问题是如何基于多个属性创建比较器,这里是另一个示例:
public static final Comparator<Employee> BY_NAME_DATE =
Comparator.comparing(Employee::getName)
.thenComparing(Employee::getDate);
你可以声明比较器对于没有自然顺序的类作为public static
字段并在需要时使用,而不是每次都在现场创建一个新的比较器。
Comparator
接口中引入了许多方便的静态方法。您可以以流畅的方式链接这些方法,因为它们都给您一个新的比较器。要组合两个比较器,可以使用thenComparing()
和thenComparingInt()
这样的方法。要学习如何使用Java-8方法构建比较器,请查看本教程。注意可能有一些复杂的情况与类型推断在Java中如何工作有关,所以我也建议阅读这个问题。
我不确定重复的日期是否会是个问题
如果员工有相同的最新日期时间信息与他们相关联,这是没有问题的,因为您想要获得第一个遇到的元素。如果流中根本没有数据,就会出现这个问题。
这就引出了第二个建议——避免在可选对象上调用get()
,除非您没有检查结果的存在(在许多情况下,这是不方便的,并且如果您发现自己执行此检查可能表明您没有充分利用Optional
API)。
如果您看一下Java 10及以上版本的文档,您将在get()
的描述中看到以下API注释:
此方法的首选替代方案是
orElseThrow()
。
方法get()
将在空可选的情况下产生NoSuchElementException
,如果你对这样的结果满意,那么应用orElseThrow()
代替,它以同样的方式起作用,使你的意图对代码的读者很明显。
该方法还有一个重载版本,允许您指定要抛出的异常类型。
Employee emp = getEmployeeList().stream()
.max(byDate)
.orElseThrow();
您不仅限于使用上面提到的方法,Optional
还提供了其他可能性,例如,您可以使用orElse()
提供默认值。
您可以简单地将thenComparing()
添加到比较器中,以便与date
和time
进行比较:
Comparator<Employee> employeeComparator = Comparator
.comparing(Employee::getDate)
.thenComparing(Employee::getTime);
有点不言自明,如果两个日期相同,它会先按date
排序,然后按time
排序。
你是正确的,如果你省略了这一点,你不应该对两个元素中哪一个有"2022-07-07"
你会得到任何假设。