使用 Java 8 流在 LocalDate 属性的对象列表中查找最近的日期

Posted

技术标签:

【中文标题】使用 Java 8 流在 LocalDate 属性的对象列表中查找最近的日期【英文标题】:Find most recent date in a list of objects on LocalDate property using Java 8 stream 【发布时间】:2019-05-12 15:29:14 【问题描述】:

我有一个包含多个属性的对象列表,其中一个是 LocalDate。我想从这个列表中找到日期最近的对象。

我对 Java 8 和使用流非常熟悉。像大多数编程一样,似乎有不止一种方法可以给这只猫剥皮。这是我目前所拥有的。

list.stream().filter( object -> object.getId() == id
&& object.getCancelDate() == null 
&& object.getEarliestDate() != null)
.min( Comparator.comparing( LocalDate::toEpochDay )
.get();

这为 Comparator 函数提供了“无法从静态上下文引用非静态方法”。

我已经研究过可能创建一个仅包含过滤对象的日期的地图,并且到目前为止已经想出了类似的东西。

list.stream().filter( object -> object.getId() == id
&& object.getCancelDate() == null 
&& object.getEarliestDate() != null)
.map( data -> data.getEarliestDate() )
.collect( Collectors.toList() )

我不确定从那里去哪里,或者这是否可行。

我知道有一种简单的方法可以做到这一点,但我的大脑并没有把这些点联系起来。

更新

感谢您的回复。我更新了我的代码 Optional<YourObject> recentObject = list.stream().filter(object -> object.getId() == id && object.getCancelDate() == null && object.getEarliestDate() != null) .max(Comparator.comparing(s -> s.getEarliestDate().toEpochDay()));

我现在得到一个编译器错误 不兼容的类型。

Required:Optional<MyClass>
Found:Optional<capture<? extends MyClass>>

该方法确实扩展了 MyClass,所以在 Optional 的类型声明中,我是否需要执行类似 MyClass.class 的操作?

更新 2 感谢@Hogen 通过在末尾添加 .map() 来帮助修复编译器错误。这是更改后的样子。

Optional<MyClass> date = 
list.stream().filter(object -> object.getId() == id &&
object.getCancelDate() == null &&
object.getEarliestDate() != null)
.max(Comparator.comparing( s -> s.getEarliestDate()
.toEpochDay())).map(Function.identity());

但是,经过一些帮助后,我能够想出一个解决方案,将地图移动到不同的位置,这样我就不会遇到使用扩展类的问题。

Optional<LocalDate> mostRecentDate = list.stream()
.filter(data -> data.getId() == id && data.getCancelDate() == null)
.map(MyObject::getEarliestDate)
.filter(Objects::nonNull)
.max(LocalDate::compareTo);

【问题讨论】:

显示类及其属性。此外,最好提供一些包含填充对象的列表,这样人们更容易测试代码。 我可以尝试为抽象类提供属性,但我不能使用实际的类和属性,因为这与工作有关。 您可能希望将您的解决方案作为补充答案,而不是作为对您问题的更新。其他人更有可能在那里找到类似问题的解决方案。如果你想麻烦,我很乐意投票。 @OleV.V.我已按照您的建议提交了我的解决方案作为补充答案。谢谢你的建议! 【参考方案1】:

你最关心的是:

Optional<YourObject> recentObject = list.stream()
        .filter(object -> object.getId() == id && object.getCancelDate() == null && object.getEarliestDate() != null)
        .max(Comparator.comparing(YourObject::getEarliestDate)); // max of the date for recency

来自LocalDate.compareTo

将此日期与另一个日期进行比较。 比较主要基于 日期,从最早到最晚。它是“与equals一致”, 由Comparable定义。

【讨论】:

也许YourObject 应该是YourClass 注意到“我想在这个列表中找到最近日期的对象”的好地方。应该通过max 而不是min 完成。注意比较器应该是.max(Comparator.comparing(s -&gt; getEarliestDate().toEpochDay())) @Aomine 为什么不比较LocalDate earliestDate 本身呢? @acousticarmor 所以你的列表就像List&lt;? extends YourObject&gt; list?然后,不幸的是,这种类型通过所有这些操作传递下来。您可以在max 之后链接.map(Function.identity())。这不会做任何事情,但会让编译器高兴(身份函数只会将接收到的YourObject 引用传回,但作为接受YourObject 作为输入的函数也将接受它的子类型(“@987654336 @”) 作为输入。 啊,是的@Holger 确实解决了这个问题。但是,我会更新评论,我确实找到了另一种不需要使用额外地图的方法。【参考方案2】:

将此作为可见性的答案。根据@nullpointer 的回答和@Holger 的建议,我想出了以下两个解决方案。

解决方案 1

Optional<MyClass> mostRecentDate = list.stream()
    .filter(myObject -> myObject.getId() == id &&
     myObject.getCancelDate() == null && myObject.getEarliestDate() != null)
    .max(Comparator.comparing( s -> s.getEarliestDate()
    .toEpochDay())).map(Function.identity());

解决方案 2

LocalDate mostRecentDate = list.stream()
    .filter(myObject -> myObject.getId() == id && myObject.getCancelDate() == null)
    .map(MyObject::getEarliestDate)
    .filter(Objects::nonNull)
    .max(LocalDate::compareTo)
    .orElse(null);

这两种解决方案都有效,但在我看来,第二种解决方案更简洁且不那么模棱两可。它删除了 .map(Function.identity()) 代码,正如@Holgen 在使用 Java 8 的新 Method Reference :: 时指出的那样,它实际上并没有做任何事情。它还过滤对象列表并将日期映射到一个新列表,然后使用 .max() 和 compareTo() 方法而不是自定义函数。我认为自定义函数和无用代码很混乱,任何阅读代码的人都可能难以理解。

请注意,在第二个解决方案中,我还删除了 Optional 类。使用 .orElse() 满足返回实际的 LocalDate 类而不是流中的选项。

感谢大家的帮助,我希望这个答案对其他人有所帮助。

【讨论】:

以上是关于使用 Java 8 流在 LocalDate 属性的对象列表中查找最近的日期的主要内容,如果未能解决你的问题,请参考以下文章

在 mongoDB 中存储 java 8 LocalDate

Java 8 Time Api 使用(LocalDate,LocalTime和LocalDateTime等)

Java 8 Time Api 使用(LocalDate,LocalTime和LocalDateTime等)

在数据库中使用Java 8 LocalDate和LocalDateTime进行Hibernate

Java 8 LocalDate:确定每月的哪个星期一(第 1、第 2、第 3 等)

JDK1.8 LocalDate 使用方式;LocalDate 封装Util,LocalDate工具类