【问题标题】:Conditionally modifying collections inline using Java Streams使用 Java 流有条件地内联修改集合
【发布时间】:2021-12-08 17:38:11
【问题描述】:

这里是 Java 11。我有 2 个List<Fizzbuzz> 实例,latest 和 current。 “最新”列表是 最新 Fizzbuzzes 的列表,在媒体上很热门。 “当前”列表是我的数据库中的 Fizbuzz 列表。我正在比较这些列表。

我需要比较这些列表并创建第三个列表additions,其中包含latest 列表中未在current 列表中找到的所有 Fizzbuzz。它是数据库中没有记录的“新” Fizzbuzz 列表。

此外,我需要将每个添加的 processedAt 字段 (Instant) 设置为相同的当前日期/时间。我想尝试使用 Java Stream API 内联完成这一切。我可以用“老式”的方式完成这个:

List<Fizzbuzz> latestList = getFromFile();
List<Fizzbuzz> currentList = getFromDatabase();
List<Fizzbuzz> additions = new ArrayList<>();
Instant now = Instant.now();
for (Fizzbuzz latest : latestList) {
    if (!currentList.contains(latest)) {
        latest.setProcessedAt(now);
        additions.add(latest);
    }
}

我使用 Java Stream API 的最佳尝试是:

List<Fizzbuzz> latestList = getFromFile();
List<Fizzbuzz> currentList = getFromDatabase();
Instant now = Instant.now();
List<Fizzbuzz> additions = latestList.stream()
    .filter(latest -> !currentList.contains(latest))
    .forEach(addition -> {
        addition.setProcessedAt(now);
    })
    .collect(Collectors.toList());

这会产生编译器错误,因为forEach 不返回任何内容。谁能发现我哪里出错了?

【问题讨论】:

  • 你想要map()而不是forEach()。
  • 那么我得到一个编译器错误:“不存在类型变量 R 的实例,因此 void 符合 R”。我认为是因为将其更改为.map(addition -&gt; addition.setProcessedAt(now)) 没有返回值?
  • 是的,您需要从map() 返回一个值。你可以用peek() 来做,但这有点不确定,因为它不应该真正修改东西。

标签: java java-stream


【解决方案1】:

您可以使用Stream.peek,它允许对每个元素应用操作并且不保留结果(如果有的话)并恢复流

List<Fizzbuzz> additions = latestList.stream()
    .filter(latest -> !currentList.contains(latest))
    .peek(addition -> addition.setProcessedAt(now))
    .collect(Collectors.toList());

要应用修改操作,将数据转换为其他内容,您需要Stream.map

【讨论】:

    【解决方案2】:

    一个设置操作和List.forEach()

    流不应该有副作用。因此,您不应在流操作中修改任何流元素。所以我建议你根本不要使用流来满足你的两个要求。

        List<Fizzbuzz> additions = new ArrayList<>(latestList);
        additions.removeAll(currentList);
        Instant now = Instant.now();
        additions.forEach(addition -> addition.setProcessedAt(now));
    

    前两行从latestList 中找到不在currentList 中的fizzbuzzes。 removeAll 方法被称为 set 操作,不是因为它适用于集合,而是因为它用于查找两个集合之间的 set 差异 (在这种情况下是两个列表)。 (其他集合操作是addAll() 用于联合,retainAll() 用于交集。)

    那么最后两行根据需要设置processedAt。

    【讨论】:

      【解决方案3】:

      您需要创建 Instant 作为最终变量才能在 lamda 表达式中使用它

      【讨论】:

      • now 实际上是最终的,因为它在初始化后没有被分配。够了。
      猜你喜欢
      • 1970-01-01
      • 2012-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多