Home > OS >  Conditionally modifying collections inline using Java Streams
Conditionally modifying collections inline using Java Streams

Time:12-09

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?

CodePudding user response:

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

CodePudding user response:

You need to create Instant as a final variable to use it in lamda expression

CodePudding user response:

A set operation and List.forEach()

Streams should not have side effects. Therefore you should not modify any stream element from within a stream operation. So I recommend that you don’t use streams at all for your two requirements.

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

The first two lines find the fizzbuzzes from latestList that are not in currentList. The removeAll method is referred to as a set operation, not because it works on sets, but because it is used for finding the something like the set difference between two collections (in this case two lists). (Other set operations are addAll() for a union and retainAll() for an intersection.)

Then the last two lines set processedAt as required.

  • Related