【问题标题】:Iterate through LocalDate wth Stream API使用 Stream API 遍历 LocalDate
【发布时间】:2021-01-29 23:09:11
【问题描述】:

我有 3 个 LocalDates(最后 3 天),对于每个日期,我想循环并执行一些操作:

StringBuilder result = "";
for (LocalDate currentDate = LocalDate.now(); currentDate.isAfter(LocalDate.now().minusDays(3));  currentDate = currentDate.minusDays(1)){
     Page<User> users = userService.getAllUsersByRegistrationDate(currentDate);
     String reportTable = reportService.getReportTable(users, tableTemplate);
     result.append(reportTable);
}

如何用 Stream API 替换这段代码或提高可读性?

【问题讨论】:

  • 使用流对这个任务来说太过分了。
  • 到目前为止你尝试过什么?
  • 不过,我没有理由结束这个问题。

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


【解决方案1】:

Java 8 解决方案

如果您真的坚持使用,您所能做的就是使用您想要过去的那几天的IntStream 创建LocalDate 的序列。然后mapToObj创建一个相关的LocalDate

LocalDate currentDate = LocalDate.now();
String result = IntStream.range(0, 3)
    .mapToObj(currentDate::minusDays)
    .map(date -> {
        Page<User> users = userService.getAllUsersByRegistrationDate(date);
        return reportService.getReportTable(users, tableTemplate);
    })
    .collect(Collectors.joining());

Java 9+ 解决方案

如果您使用或更高版本,您可以利用无限Stream的优势,不断生成项目,直到满足某个条件。

三参数 Stream.iterate​(T seed, Predicate&lt;? super T&gt; hasNext, UnaryOperator&lt;T&gt; next)

LocalDate threeDaysAgo = currentDate.minusDays(3);
String result = Stream.iterate(
        LocalDate.now(), 
        date -> date.isAfter(threeDaysAgo), 
        date -> date.minusDays(1))
    .map(date -> {
        Page<User> users = userService.getAllUsersByRegistrationDate(date);
        return reportService.getReportTable(users, tableTemplate);
    })
    .collect(Collectors.joining());

一种新方法 Stream::takeWhile(Predicate&lt;? super T&gt; predicate)

LocalDate threeDaysAgo = currentDate.minusDays(3);
String result = Stream.iterate(LocalDate.now(), date -> date.minusDays(1))
    .takeWhile(date -> date.isAfter(threeDaysAgo))
    .map(date -> {
         Page<User> users = userService.getAllUsersByRegistrationDate(date);
         return reportService.getReportTable(users, tableTemplate);
    })
    .collect(Collectors.joining());

以上所有示例都生成 3 个 LocalDate 实例,因为今天是 2020-10-15,它们将在过去 3 天内拥有:2020-10-152020-10-142020-10-13,并通过 Stream&lt;LocalDate&gt; 提供它们以供进一步处理.

免责声明:我发现 for 循环更具可读性。不要指望“转换”的 for 循环到 Stream API 会自动增加可读性和简洁性。在很多情况下,它不会。

【讨论】:

  • 你的收集步骤不就跟.collect(Collectors.joining());一样吗?
【解决方案2】:

LocalDate.datesUntil(LocalDate, Period)

我觉得你的代码很好。如果您想使用流操作,或者您只是好奇它的外观,从 Java 9 开始您可以这样做:

    LocalDate today = LocalDate.now(ZoneId.of("Africa/Timbuktu"));
    today.datesUntil(today.minusDays(3), Period.ofDays(-1))
            .forEach(ld -> {
                System.out.println("Now doing something with date " + ld);
            });

刚刚运行时的输出:

Now doing something with date 2020-10-15
Now doing something with date 2020-10-14
Now doing something with date 2020-10-13

LocalDate.datesUntil() 与负周期一起工作并没有很好的记录,但它确实会返回一个 LocalDate 对象流。

(我知道在这种情况下 lambda 中的花括号是不必要的,但从您的问题看来,您想为每个日期执行多个语句,因此它们当然是必要的。如果您只想要在那里调用一个方法,您可能只需要一行。.forEach(ld -&gt; System.out.println("Now doing something with date " + ld))。)

文档链接:LocalDate.datesUntil()

【讨论】:

  • 哇,不知道有这种方法。太好了,它返回Stream&lt;LocalDate&gt;,因此可以继续处理。
  • 不幸的是,Java 9 发布了这些方便的方法...
猜你喜欢
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
相关资源
最近更新 更多