Java流:查找基于两个属性的最大元素



我有一个具有这种结构的对象列表

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字段并在需要时使用,而不是每次都在现场创建一个新的比较器

Java 8在Comparator接口中引入了许多方便的静态方法。您可以以流畅的方式链接这些方法,因为它们都给您一个新的比较器。要组合两个比较器,可以使用thenComparing()thenComparingInt()这样的方法。要学习如何使用Java-8方法构建比较器,请查看本教程

注意可能有一些复杂的情况与类型推断在Java中如何工作有关,所以我也建议阅读这个问题

我不确定重复的日期是否会是个问题

如果员工有相同的最新日期时间信息与他们相关联,这是没有问题的,因为您想要获得第一个遇到的元素。如果流中根本没有数据,就会出现这个问题。

这就引出了第二个建议——避免在可选对象上调用get(),除非您没有检查结果的存在(在许多情况下,这是不方便的,并且如果您发现自己执行此检查可能表明您没有充分利用OptionalAPI)。

如果您看一下Java 10及以上版本的文档,您将在get()的描述中看到以下API注释:

此方法的首选替代方案是orElseThrow()

方法get()将在空可选的情况下产生NoSuchElementException,如果你对这样的结果满意,那么应用orElseThrow()代替,它以同样的方式起作用,使你的意图对代码的读者很明显。

该方法还有一个重载版本,允许您指定要抛出的异常类型。

Employee emp = getEmployeeList().stream()
.max(byDate)
.orElseThrow();

您不仅限于使用上面提到的方法,Optional还提供了其他可能性,例如,您可以使用orElse()提供默认值。

您可以简单地将thenComparing()添加到比较器中,以便与datetime进行比较:

Comparator<Employee> employeeComparator = Comparator
.comparing(Employee::getDate)
.thenComparing(Employee::getTime);

有点不言自明,如果两个日期相同,它会先按date排序,然后按time排序。

你是正确的,如果你省略了这一点,你不应该对两个元素中哪一个有"2022-07-07"你会得到任何假设。

相关内容

  • 没有找到相关文章

最新更新