【问题标题】:Java8 filter arraylist with custom object on field dateJava8过滤器数组列表与字段日期的自定义对象
【发布时间】:2021-04-02 05:07:03
【问题描述】:

我必须在字段issueDate(输入String)上过滤List<Card>,其中卡片要显示到最近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());  

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

谁能提出一个解决这个问题的好方法?

【问题讨论】:

  • 我不明白。 Streams 是在 Java 8 中添加的,那么你为什么要标记你的问题 java-7?而且由于您使用的是 Java 8,因此请使用 java.time 包中的类来解析字符串,而不是使用 SimpleDateFormat 类。
  • 我建议你不要使用SimpleDateFormatDate。这些类设计不佳且早已过时,尤其是前者,尤其是出了名的麻烦。而是使用来自java.time, the modern Java date and time APILocalDate
  • 迭代几百张卡片并不需要很长时间。无论是使用for 循环还是其他方式。

标签: arraylist java-8 java-stream simpledateformat java-time


【解决方案1】:

你的代码有很多问题:

  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 的更多信息。

【讨论】:

    【解决方案2】:

    不确定是否需要在此处解析日期。您所有的日期都是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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-15
      • 2011-09-03
      • 1970-01-01
      • 2018-07-10
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      • 2016-04-23
      相关资源
      最近更新 更多