使用 Java 流有条件地内联修改集合

Conditionally modifying collections inline using Java Streams

Java 11 在这里。我有 2 个 List<Fizzbuzz> 个实例,latestcurrent。 “最新”列表是最新 热门话题列表。 “当前”列表是我数据库中的 Fizbuzze 列表。我正在比较这些列表。

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

此外,我需要将每个添加的 processedAt 字段 (Instant) 设置为相同的当前 date/time。我想尝试使用 Java 流 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 流 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 没有 return 任何东西。谁能发现我哪里出错了?

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

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

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

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

一个集合操作和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 方法被称为 集合操作 ,不是因为它适用于集合,而是因为它用于查找类似 集合差异的东西 在两个集合之间(在本例中是两个列表)。 (其他集合操作是 addAll() 用于并集,retainAll() 用于交集。)

然后最后两行根据需要设置processedAt