javajava-stream

Conditionally modifying collections inline using Java Streams


Java 11 here. I have a 2 List<Fizzbuzz> instances, latest and current. The "latest" list is the list of latest Fizzbuzzes, hot off the press. The "current" list is the list of Fizbuzzes that I have in my database. I am comparing these lists.

I need to compare these lists and create a 3rd list, additions, which contains any Fizzbuzzes from the latest list that are not found inside the current list. Its a list of "new" Fizzbuzzes that the database does not have on record.

Furthermore, I need to set each addition's processedAt field (Instant) to the same current date/time. I'd like to try and accomplish this all inline using the Java Stream API. I can accomplish this the "old fashioned" way:

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);
    }
}

My best attempt using the Java Stream API is:

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());

This generates a compiler error because forEach doesn't return anything. Can anyone spot where I'm going awry?


Solution

  • You may use Stream.peek, it allows to apply an operation on each element and doesn't keep the result (if there is any) and resume the stream

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

    To a apply a modifying operation, that would transform the data into something else, you need Stream.map