1

I have the following list

List<CompletableFuture<Name>> myList;

The Name class contains the following properties.

String name;
boolean available;

How can I count the total number of name objects which have the available property set to true?

2
  • myList.stream().map(CompletableFuture::get).filter(f->f.available).count() ? Just wrap get catching InterruptedExcetion
    – gdomo
    Commented Aug 7, 2023 at 19:54
  • @gdomo you can also use CompletableFuture::join, which throws unchecked exception
    – mlecz
    Commented Aug 7, 2023 at 19:56

2 Answers 2

0

You first need to wait for the completion of the Futures, then you could can filter() the ones with available set to true and last but not least count() the amount of list items left. For all of that I am using the Java Stream API.

import java.util.ArrayList;
import java.util.concurrent.CompletableFuture;

public class Main {
    record Name(String name, boolean available){};

    public static void main(String[] args) {
        var input = new ArrayList<CompletableFuture<Name>>();
        input.add(CompletableFuture.completedFuture(new Name("Thomas", true)));
        input.add(CompletableFuture.completedFuture(new Name("John", true)));
        input.add(CompletableFuture.completedFuture(new Name("Pat", false)));
        var total = input.stream()
                .map(CompletableFuture::join)
                .filter(name -> name.available)
                .count();
        System.out.println(total);
    }
}

Expected output:

2

In terms of waiting for the Futures to complete have a look at this StackOverflow thread which discusses some of the available options and their behavior in more detail.

0

If you want a synchronous result

Getting the result synchronously is easy.

static int countNames(List<CompletableFuture<Name>> names) {
    int count = 0;
    for (CompletableFuture<Name> futureName: names) {
        if (futureName.join().available) { // this is where you'd get exceptions
            count++;
        }
    }
    return count;
}

The only problem is that you'll get exceptions propagated to you, and you'll have to wait for every future to complete in order.

If you want an asynchronous result

This method gives you a result that is also a Future, allowing you to continue a promise-like flow.

static Future<Integer> countNames(List<CompletableFuture<Name>> names) {
    CompletableFuture<Integer> tally = CompletableFuture.completedFuture(0);
    for (CompletableFuture<Name> futureName: names) {
        tally = futureName.thenCombine(tally, (name, count) -> name.available ? count + 1 : count);
    }
    return tally;
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.