Java8 过滤器数组列表与字段日期上的自定义对象

问题描述

我必须在字段 List<Card>(类型 issueDate)上过滤 String,其中卡片要显示到过去 7 年的日期。

我尝试过的解决方案是将 issueDate 字段从 String 解析为 Date,然后应用 date.after(startDate)date.before(endDate) 如下:>

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
cardList.stream()
        .map(s->s.getIssueDate())
        .filter(dt -> sdf.parse(dt).after(sdf.parse("2020-06-08")) && 
                      sdf.parse(dt).before(sdf.parse("2020-08-12")))
        .collect(Collectors.toList());  

甚至不能申请循环,因为可能有数百张发卡,并且它通过迭代每个发卡日期(字符串到日期和检查年份)来影响性能

谁能建议一个好的解决方案?

解决方法

您的代码有很多问题:

  1. java.util 日期时间 API 及其格式 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern date-time API*
  2. 您应该将 issueDate 声明为 LocalDate(或 Date,如果您仍想坚持使用旧 API)而不是 String。但是,无论出于何种原因,如果您仍希望将其保留为 String,您可以更改代码以在 Stream 处理期间仅将其解析为日期类型对象一次(目前,您正在执行两次)。
  3. 您正在 Stream 处理内部解析 2020-06-082020-08-12,而它们是静态值,因此它们应该在 Stream 处理之外解析。事实上,如果这些静态日期不是String,你可以直接创建日期类型的对象,例如LocalDate start = LocalDate.of(2020,6,8)

这些建议已包含在以下代码中:

LocalDate start = LocalDate.parse("2020-06-08");
LocalDate end = LocalDate.parse("2020-08-12");

List<LocalDate> dates = 
        cardList.stream()
                .map(card -> LocalDate.parse(card.getIssueDate()))
                .filter(ld -> ld.isAfter(start) && ld.isBefore(end))
                .collect(Collectors.toList());

如果你想把Stream收集到卡片列表中,你可以这样做:

List<Card> cards = 
        cardList.stream()
                .filter(card -> {
                    LocalDate ld = LocalDate.parse(card.getIssueDate());                            
                    return ld.isAfter(start) && ld.isBefore(end);
                })
                .collect(Collectors.toList());

* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project。从 Trail: Date Time 了解有关现代日期时间 API 的更多信息。

,

不确定您是否需要在此处解析日期。您的所有日期都是 String 并且具有相同的 yyyy-MM-dd 格式。

在这种特殊情况下,您可以简单地按字典顺序比较字符串:

String from = "2020-06-08";
String to = "2020-08-12";

List<Card> filteredCardList = 
    cardList.stream()
            .filter(card -> card.getIssueDate().compareTo(from) > 0)
            .filter(card -> card.getIssueDate().compareTo(to) < 0)
            .collect(toList());

或者你对普通的旧循环做同样的事情:

List<Card> filteredCardList = new ArrayList<>();
for(Card card : cardList) {
    String date = card.getIssueDate();
    if(date.compareTo(from) > 0 && date.compareTo(to) < 0) {
        filteredCardList.add(card);
    }
}