使用 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 -> getEarliestDate().toEpochDay()))
@Aomine 为什么不比较LocalDate earliestDate
本身呢?
@acousticarmor 所以你的列表就像List<? extends YourObject> 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